Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.m2e.core/src/org/eclipse/m2e/core')
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenImages.java222
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenPlugin.java564
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/NoSuchComponentException.java29
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AbstractMavenMenuCreator.java99
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AddDependencyAction.java75
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AddPluginAction.java65
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/ChangeNatureAction.java161
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/CheckoutAsMavenAction.java91
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/DisableNatureAction.java81
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/EnableNatureAction.java141
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MaterializeAction.java58
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenActionSupport.java136
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenConsoleRemoveAction.java31
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenDebugOutputAction.java63
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenMenuAction.java157
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenPropertyTester.java52
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/ModuleProjectWizardAction.java61
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenMavenConsoleAction.java29
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenPomAction.java404
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenUrlAction.java230
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/RefreshMavenModelsAction.java114
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/SelectionUtil.java360
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/UpdateConfigurationAction.java160
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeCatalogFactory.java185
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeCatalogsWriter.java167
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeManager.java117
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/AbstractEclipseBuildContext.java141
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/ChangedFileOutputStream.java104
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/EclipseBuildContext.java75
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/EclipseIncrementalBuildContext.java142
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/ResourceDeltaScanner.java96
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/IMavenConsoleListener.java27
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/IMavenConstants.java87
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/MavenConsole.java41
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/MavenLogger.java59
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/Messages.java55
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/AbstractMavenConfigurationChangeListener.java22
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactKey.java148
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactRef.java73
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactRepositoryRef.java69
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ILocalRepositoryListener.java29
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java224
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java66
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfigurationChangeListener.java25
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenLauncherConfiguration.java39
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ISettingsChangeListener.java26
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenConfigurationChangeEvent.java47
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenModelManager.java581
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenRuntime.java44
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenRuntimeManager.java165
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/NearestVersionConflictResolver.java257
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ProjectUpdater.java25
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IIndex.java134
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IMutableIndex.java37
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexListener.java33
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexManager.java53
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexedArtifact.java151
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexedArtifactFile.java104
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/MatchTyped.java27
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/MatchTypedStringSearchExpression.java29
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/SearchExpression.java25
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/SourcedSearchExpression.java23
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/StringSearchExpression.java29
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/UserInputSearchExpression.java23
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/ExtensionReader.java130
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Messages.java1024
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/actions/DefaultMavenMenuCreator.java139
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/InternalBuildParticipant.java76
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilder.java302
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenNature.java87
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/ResourceScanner.java91
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/console/ConsoleDocument.java95
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/console/MavenConsoleImpl.java404
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomFileContentDescriber.java96
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomHandler.java166
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/TextContentDescriber.java89
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/XMLContentDescriber.java128
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/AbstractTransferListenerAdapter.java107
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ArtifactTransferListenerAdapter.java59
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ContextRepositorySystemSession.java18
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ContextRepositorySystemSessionImpl.java153
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/DefaultMavenComponentContributor.java38
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseBuildContext.java25
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseClassRealmManagerDelegate.java88
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLocalRepositoryMaintainer.java56
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLogger.java135
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLoggerManager.java62
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ExtensionModule.java53
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/IMavenComponentContributor.java27
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenConfigurationImpl.java107
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenEmbeddedRuntime.java198
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenExternalRuntime.java239
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java1098
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenWorkspaceRuntime.java141
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/WagonTransferListenerAdapter.java118
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/ArtifactScanningMonitor.java67
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/AsyncFetcher.java283
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/CompositeIndex.java118
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/EquinoxLock.java35
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/EquinoxLocker.java41
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexUpdaterJob.java90
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexedArtifactGroup.java57
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexesExtensionReader.java84
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexingTransferListener.java34
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/NexusIndex.java180
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/NexusIndexManager.java1312
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecycle/LifecycleMappingFactory.java238
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/messages.properties498
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceConstants.java88
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceInitializer.java67
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ArtifactKeyAdapterFactory.java66
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/DependencyResolutionContext.java75
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/EclipseMavenMetadataCache.java91
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/IManagedCache.java31
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/IgnoreMojoProjectConfiguration.java33
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MavenMarkerManager.java713
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MavenProjectImportResult.java37
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MissingLifecycleMapping.java87
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MojoExecutionProjectConfigurator.java93
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MojoExecutionUtils.java29
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ProjectConfigurationManager.java716
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/WorkspaceStateWriter.java87
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/AbstractMavenDependencyResolver.java58
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/BasicProjectRegistry.java151
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/Capability.java39
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/DefaultMavenDependencyResolver.java98
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipsePluginDependenciesResolver.java66
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipseWorkspaceArtifactRepository.java159
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ILifecycleMapping2.java25
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/IProjectRegistry.java34
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenCapability.java86
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenProjectFacade.java382
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenRequiredCapability.java101
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MutableProjectRegistry.java245
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistry.java117
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryManager.java854
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryReader.java216
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryRefreshJob.java233
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/RequiredCapability.java50
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/StaleMutableProjectRegistryException.java23
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/VersionlessKey.java65
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/IRepositoryDiscoverer.java29
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/IRepositoryIndexer.java46
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryInfo.java175
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryRegistry.java323
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryRegistryUpdateJob.java65
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/jobs/IBackgroundProcessingQueue.java31
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/messages.properties152
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/AbstractProjectScanner.java55
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenMarkerManager.java54
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectChangedListener.java21
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectFacade.java163
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectImportResult.java32
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectVisitor.java41
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectVisitor2.java29
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IProjectConfigurationManager.java66
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/LocalProjectScanner.java187
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectChangedEvent.java69
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectInfo.java198
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectManager.java166
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectPomScanner.java219
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectScmInfo.java108
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectUtils.java98
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenUpdateRequest.java124
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/ProjectImportConfiguration.java142
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/ResolverConfiguration.java56
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractBuildParticipant.java68
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractLifecycleMapping.java219
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractProjectConfigurator.java243
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/CustomizableLifecycleMapping.java40
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/DefaultLifecycleMapping.java121
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/ILifecycleMapping.java56
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MavenProjectConfigurator.java120
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MavenResourcesProjectConfigurator.java20
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MojoExecutionBuildParticipant.java61
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/NoopLifecycleMapping.java55
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/PluginExecutionFilter.java81
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/ProjectConfigurationRequest.java72
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/repository/IRepository.java98
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/repository/IRepositoryRegistry.java70
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/MavenCheckoutOperation.java129
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandler.java131
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandlerFactory.java152
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandlerUi.java80
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmTag.java53
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmUrl.java100
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/AbstractMavenDialog.java124
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/AddDependencyDialog.java617
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/EditDependencyDialog.java217
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/InputHistory.java232
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenGoalSelectionDialog.java359
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenMessageDialog.java87
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenPropertyDialog.java192
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenRepositorySearchDialog.java184
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenAdapterFactory.java67
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenConsoleFactory.java32
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenConsolePageParticipant.java108
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenShowConsoleAction.java83
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenVersionDecorator.java112
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/components/TextComboBoxCellEditor.java103
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/AbstractLifecyclePropertyPage.java57
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/AbstractPropertyPageExtensionPoint.java67
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ILifecyclePropertyPage.java60
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ILifecyclePropertyPageExtensionPoint.java55
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/LifecycleMappingPropertyPageFactory.java143
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTable.java107
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTableContentProvider.java61
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTableLabelProvider.java96
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/CustomizableLifecycleMappingPropertyPage.java58
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/EmptyLifecycleMappingPropertyPage.java27
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/GoalsFieldEditor.java196
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/LocalArchetypeCatalogDialog.java230
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenArchetypesPreferencePage.java320
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenGoalSelectionAdapter.java73
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenInstallationsPreferencePage.java677
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenPreferencePage.java104
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenProjectLifecycleMappingPage.java97
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenProjectPreferencePage.java167
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenSettingsPreferencePage.java413
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MissingLifecycleMappingPropertyPage.java40
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/ProblemReportingPreferencePage.java57
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/RemoteArchetypeCatalogDialog.java284
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/SimpleLifecycleMappingPropertyPage.java62
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchPage.java141
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchResult.java76
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchResultPage.java80
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/MavenRepositoryView.java596
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/RepositoryViewContentProvider.java86
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/RepositoryViewLabelProvider.java97
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/AbstractIndexedRepositoryNode.java86
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/AbstractRepositoriesNode.java77
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/CustomRepositoriesNode.java35
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/GlobalRepositoriesNode.java36
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IArtifactNode.java22
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IMavenRepositoryNode.java28
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactFileNode.java91
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactGroupNode.java101
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactNode.java92
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/LocalRepositoryNode.java38
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/LocalRepositoryRootNode.java55
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/ProjectRepositoriesNode.java66
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/RepositoryNode.java56
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/WorkspaceRepositoryNode.java32
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/M2EErrorDialog.java218
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/M2EUtils.java108
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/ProposalUtil.java156
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/Util.java119
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/ArtifactInfo.java78
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/CComboContentAdapter.java96
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/ControlDecoration.java1088
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/IndexSearchEngine.java185
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/MenuDetectEvent.java77
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/MenuDetectListener.java43
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/Packaging.java47
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/SearchEngine.java49
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/SearchException.java29
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/AbstractMavenWizardPage.java218
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/CustomArchetypeDialog.java252
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenArtifactComponent.java270
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenCheckoutLocationPage.java424
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenCheckoutWizard.java180
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenDependenciesWizardPage.java291
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenImportWizard.java113
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenImportWizardPage.java525
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileArtifactWizardPage.java390
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileRepositoryWizardPage.java149
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileWizard.java151
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenLocationComponent.java193
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenMaterializePomWizard.java241
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenModuleWizard.java305
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenModuleWizardParentPage.java310
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenParentComponent.java223
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomSelectionComponent.java580
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomWizard.java174
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomWizardPage.java223
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectCheckoutJob.java256
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectSelectionDialog.java192
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizard.java358
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArchetypePage.java953
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArchetypeParametersPage.java617
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArtifactPage.java364
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardLocationPage.java321
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ProjectsImportPage.java627
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ProjectsImportWizard.java48
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ResolverConfigurationComponent.java156
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/WidthGroup.java53
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/WorkingSetGroup.java271
287 files changed, 45186 insertions, 0 deletions
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenImages.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenImages.java
new file mode 100644
index 00000000..2c58294d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenImages.java
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.viewers.DecorationOverlayIcon;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class MavenImages {
+
+ // object images
+
+ public static final Image IMG_CLEAR = createImage("clear.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_CLEAR_DISABLED = createImage("clear_disabled.gif"); //$NON-NLS-1$
+
+ public static final String PATH_JAR = "jar_obj.gif"; //$NON-NLS-1$
+
+ public static final Image IMG_JAR = createImage(PATH_JAR);
+
+ public static final String PATH_LOCK = "lock_ovr.gif"; //$NON-NLS-1$
+
+ public static final String PATH_VERSION = "jar_version.gif"; //$NON-NLS-1$
+
+ public static final Image IMG_VERSION = createImage(PATH_VERSION);
+
+ public static final String PATH_VERSION_SRC = "jar_src_version.gif"; //$NON-NLS-1$
+
+ public static final Image IMG_VERSION_SRC = createImage(PATH_VERSION_SRC);
+
+ public static final Image IMG_JAVA = createImage("java_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_JAVA_SRC = createImage("java_src_obj.gif"); //$NON-NLS-1$
+
+ // public static final Image IMG_M2 = createImage("m2.gif");
+
+ public static final Image IMG_LAUNCH_MAIN = createImage("main_tab.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_INDEX = createImage("maven_index.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_INDEXES = createImage("maven_indexes.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_MAVEN_JAR = createImage("mjar.gif"); //$NON-NLS-1$
+
+ // public static final Image IMG_JAR = createImage("mlabel.gif");
+
+ public static final Image IMG_NEW_POM = createImage("new_m2_pom.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_NEW_PROJECT = createImage("new_m2_project.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_OPEN_POM = createImage("open_pom.gif"); //$NON-NLS-1$
+
+ // public static final Image IMG_POM = createImage("pom_obj.gif");
+
+ public static final Image IMG_UPD_DEPENDENCIES = createImage("update_dependencies.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_UPD_SOURCES = createImage("update_source_folders.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_WEB = createImage("web.gif"); //$NON-NLS-1$
+
+ // wizard images
+
+ public static final ImageDescriptor WIZ_IMPORT_WIZ = createDescriptor("import_project.png"); //$NON-NLS-1$
+
+ public static final ImageDescriptor WIZ_NEW_PROJECT = createDescriptor("new_m2_project_wizard.gif"); //$NON-NLS-1$
+
+ // descriptors
+
+ public static final ImageDescriptor M2 = createDescriptor("m2.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor DEBUG = createDescriptor("debug.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor ADD_INDEX = createDescriptor("add_index.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor CLOSE = createDescriptor("close.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor COPY = createDescriptor("copy.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor COLLAPSE_ALL = createDescriptor("collapseall.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor EXPAND_ALL = createDescriptor("expandall.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor NEW_POM = createDescriptor("new_m2_pom.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor REFRESH = createDescriptor("refresh.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor UPD_INDEX = createDescriptor("update_index.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor REBUILD_INDEX = createDescriptor("rebuild_index.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor POM = createDescriptor("pom_obj.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor IMPORT_PROJECT = createDescriptor("import_m2_project.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor SHOW_CONSOLE_ERR = createDescriptor("stderr.gif"); //$NON-NLS-1$
+
+ public static final ImageDescriptor SHOW_CONSOLE_OUT = createDescriptor("stdout.gif"); //$NON-NLS-1$
+
+ private static ImageDescriptor createDescriptor(String key) {
+ try {
+ ImageRegistry imageRegistry = getImageRegistry();
+ if(imageRegistry != null) {
+ ImageDescriptor imageDescriptor = imageRegistry.getDescriptor(key);
+ if(imageDescriptor==null) {
+ imageDescriptor = doCreateDescriptor(key);
+ imageRegistry.put(key, imageDescriptor);
+ }
+ return imageDescriptor;
+ }
+ } catch(Exception ex) {
+ MavenLogger.log(key, ex);
+ }
+ return null;
+ }
+
+ private static Image createImage(String key) {
+ createDescriptor(key);
+ ImageRegistry imageRegistry = getImageRegistry();
+ return imageRegistry == null ? null : imageRegistry.get(key);
+ }
+
+ private static ImageRegistry getImageRegistry() {
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ return plugin == null ? null : plugin.getImageRegistry();
+ }
+
+ private static ImageDescriptor doCreateDescriptor(String image) {
+ return AbstractUIPlugin.imageDescriptorFromPlugin(IMavenConstants.PLUGIN_ID, "icons/" + image); //$NON-NLS-1$
+ }
+
+
+
+ private static ImageDescriptor createImageDescriptor( String key, ImageData imageData )
+ {
+ try
+ {
+ ImageRegistry imageRegistry = getImageRegistry();
+ if ( imageRegistry != null )
+ {
+ ImageDescriptor imageDescriptor = imageRegistry.getDescriptor( key );
+ if ( imageDescriptor != null )
+ {
+ imageRegistry.remove( key );
+ }
+ {
+ imageDescriptor = ImageDescriptor.createFromImageData( imageData );
+ imageRegistry.put( key, imageDescriptor );
+ }
+ return imageDescriptor;
+ }
+ }
+ catch ( Exception ex )
+ {
+ MavenLogger.log(key, ex);
+ }
+ return null;
+ }
+
+ private static ImageDescriptor getOverlayImageDescriptor( String basekey, String overlaykey, int quadrant )
+ {
+ String key = basekey + overlaykey;
+ try
+ {
+ ImageRegistry imageRegistry = getImageRegistry();
+ if ( imageRegistry != null )
+ {
+ ImageDescriptor imageDescriptor = imageRegistry.getDescriptor( key );
+ if ( imageDescriptor == null )
+ {
+ ImageDescriptor base = createDescriptor( basekey );
+ ImageDescriptor overlay = createDescriptor( overlaykey );
+ if ( base == null || overlay == null )
+ {
+ MavenLogger.log( "cannot construct overlay image descriptor for " + basekey + " " + overlaykey );
+ return null;
+ }
+ imageDescriptor = createOverlayDescriptor( base, overlay, quadrant );
+ imageRegistry.put( key, imageDescriptor );
+ }
+ return imageDescriptor;
+ }
+ }
+ catch ( Exception ex )
+ {
+ MavenLogger.log(key, ex);
+ }
+ return null;
+ }
+
+ public static Image getOverlayImage( String base, String overlay, int quadrant )
+ {
+ getOverlayImageDescriptor( base, overlay, quadrant );
+ ImageRegistry imageRegistry = getImageRegistry();
+ return imageRegistry == null ? null : imageRegistry.get( base + overlay );
+ }
+
+
+ private static ImageDescriptor createOverlayDescriptor( ImageDescriptor base, ImageDescriptor overlay, int quadrant )
+ {
+ return new DecorationOverlayIcon( base.createImage(), overlay, quadrant );
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenPlugin.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenPlugin.java
new file mode 100644
index 00000000..07717168
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/MavenPlugin.java
@@ -0,0 +1,564 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IStartup;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.IWebBrowser;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import org.codehaus.plexus.ContainerConfiguration;
+import org.codehaus.plexus.DefaultContainerConfiguration;
+import org.codehaus.plexus.DefaultPlexusContainer;
+import org.codehaus.plexus.MutablePlexusContainer;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.classworlds.ClassWorld;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+
+import org.apache.maven.archetype.Archetype;
+import org.apache.maven.archetype.common.ArchetypeArtifactManager;
+import org.apache.maven.archetype.source.ArchetypeDataSource;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.manager.WagonManager;
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.artifact.resolver.ArtifactCollector;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.index.ArtifactContextProducer;
+import org.apache.maven.index.NexusIndexer;
+import org.apache.maven.index.updater.IndexUpdater;
+import org.apache.maven.plugin.LegacySupport;
+
+import org.sonatype.aether.RepositorySystem;
+
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory;
+import org.eclipse.m2e.core.archetype.ArchetypeManager;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.embedder.MavenModelManager;
+import org.eclipse.m2e.core.embedder.MavenRuntimeManager;
+import org.eclipse.m2e.core.index.IndexManager;
+import org.eclipse.m2e.core.internal.ExtensionReader;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.console.MavenConsoleImpl;
+import org.eclipse.m2e.core.internal.embedder.MavenConfigurationImpl;
+import org.eclipse.m2e.core.internal.embedder.MavenEmbeddedRuntime;
+import org.eclipse.m2e.core.internal.embedder.MavenImpl;
+import org.eclipse.m2e.core.internal.embedder.MavenWorkspaceRuntime;
+import org.eclipse.m2e.core.internal.index.IndexesExtensionReader;
+import org.eclipse.m2e.core.internal.index.IndexingTransferListener;
+import org.eclipse.m2e.core.internal.index.NexusIndexManager;
+import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
+import org.eclipse.m2e.core.internal.project.MavenMarkerManager;
+import org.eclipse.m2e.core.internal.project.ProjectConfigurationManager;
+import org.eclipse.m2e.core.internal.project.WorkspaceStateWriter;
+import org.eclipse.m2e.core.internal.project.registry.ProjectRegistryManager;
+import org.eclipse.m2e.core.internal.project.registry.ProjectRegistryRefreshJob;
+import org.eclipse.m2e.core.internal.repository.RepositoryRegistry;
+import org.eclipse.m2e.core.project.IMavenMarkerManager;
+import org.eclipse.m2e.core.project.IProjectConfigurationManager;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.project.MavenUpdateRequest;
+import org.eclipse.m2e.core.repository.IRepositoryRegistry;
+import org.eclipse.m2e.core.util.search.IndexSearchEngine;
+import org.eclipse.m2e.core.util.search.SearchEngine;
+
+
+/**
+ * MavenPlugin main plug-in class.
+ */
+public class MavenPlugin extends AbstractUIPlugin implements IStartup {
+
+ // preferences
+ private static final String PREFS_ARCHETYPES = "archetypesInfo.xml"; //$NON-NLS-1$
+
+ // The shared instance
+ private static MavenPlugin plugin;
+
+ /**
+ * General purpose plexus container. Contains components from maven embedder and all other bundles visible from this
+ * bundle's classloader.
+ */
+ private MutablePlexusContainer plexus;
+
+ private MavenConsole console;
+
+ private MavenModelManager modelManager;
+
+ private NexusIndexManager indexManager;
+
+ private BundleContext bundleContext;
+
+ private MavenProjectManager projectManager;
+
+ private MavenRuntimeManager runtimeManager;
+
+ private ProjectConfigurationManager configurationManager;
+
+ private ProjectRegistryRefreshJob mavenBackgroundJob;
+
+ private ArchetypeManager archetypeManager;
+
+ private ProjectRegistryManager managerImpl;
+
+ private IMavenMarkerManager mavenMarkerManager;
+
+ private RepositoryRegistry repositoryRegistry;
+
+ private String version = "0.0.0"; //$NON-NLS-1$
+
+ private String qualifiedVersion = "0.0.0.qualifier"; //$NON-NLS-1$
+
+ private IMavenConfiguration mavenConfiguration;
+
+ private MavenImpl maven;
+
+ public MavenPlugin() {
+ plugin = this;
+
+ if(Boolean.parseBoolean(Platform.getDebugOption(IMavenConstants.PLUGIN_ID + "/debug/initialization"))) { //$NON-NLS-1$
+ System.err.println("### executing constructor " + IMavenConstants.PLUGIN_ID); //$NON-NLS-1$
+ new Throwable().printStackTrace();
+ }
+ }
+
+ public IMaven getMaven() {
+ return maven;
+ }
+
+ /**
+ * This method is called upon plug-in activation
+ */
+ public void start(final BundleContext context) throws Exception {
+ super.start(context);
+
+ if(Boolean.parseBoolean(Platform.getDebugOption(IMavenConstants.PLUGIN_ID + "/debug/initialization"))) { //$NON-NLS-1$
+ System.err.println("### executing start() " + IMavenConstants.PLUGIN_ID); //$NON-NLS-1$
+ new Throwable().printStackTrace();
+ }
+
+ this.bundleContext = context;
+
+ try {
+ this.qualifiedVersion = (String) getBundle().getHeaders().get(Constants.BUNDLE_VERSION);
+ Version bundleVersion = Version.parseVersion(this.qualifiedVersion);
+ this.version = bundleVersion.getMajor() + "." + bundleVersion.getMinor() + "." + bundleVersion.getMicro(); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch(IllegalArgumentException e) {
+ // ignored
+ }
+
+ MavenLogger.setLog(getLog());
+
+ try {
+ this.console = new MavenConsoleImpl(MavenImages.M2); //$NON-NLS-1$
+ } catch(RuntimeException ex) {
+ MavenLogger.log(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, "Unable to start console: "
+ + ex.toString(), ex));
+ }
+
+ this.mavenConfiguration = new MavenConfigurationImpl(getPreferenceStore());
+
+ ClassLoader cl = MavenPlugin.class.getClassLoader();
+ ContainerConfiguration cc = new DefaultContainerConfiguration().setClassWorld(new ClassWorld("plexus.core", cl)) //$NON-NLS-1$
+ .setName("plexus"); //$NON-NLS-1$
+ this.plexus = new DefaultPlexusContainer(cc);
+
+ File stateLocationDir = getStateLocation().toFile();
+
+ // TODO this is broken, need to make it lazy, otherwise we'll deadlock or timeout... or both
+ this.archetypeManager = newArchetypeManager(stateLocationDir);
+ try {
+ this.archetypeManager.readCatalogs();
+ } catch(Exception ex) {
+ String msg = "Can't read archetype catalog configuration";
+ this.console.logError(msg + "; " + ex.getMessage()); //$NON-NLS-1$
+ MavenLogger.log(msg, ex);
+ }
+
+ this.mavenMarkerManager = new MavenMarkerManager(console, mavenConfiguration);
+
+ boolean updateProjectsOnStartup = mavenConfiguration.isUpdateProjectsOnStartup();
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+
+ this.maven = new MavenImpl(mavenConfiguration, console);
+
+ // TODO eagerly reads workspace state cache
+ this.managerImpl = new ProjectRegistryManager(maven, console, stateLocationDir,
+ !updateProjectsOnStartup /* readState */, mavenMarkerManager);
+
+ this.mavenBackgroundJob = new ProjectRegistryRefreshJob(managerImpl, console, mavenConfiguration);
+
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ workspace.addResourceChangeListener(mavenBackgroundJob, IResourceChangeEvent.POST_CHANGE
+ | IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_DELETE);
+
+ this.projectManager = new MavenProjectManager(managerImpl, mavenBackgroundJob, stateLocationDir);
+ this.projectManager.addMavenProjectChangedListener(new WorkspaceStateWriter(projectManager));
+ if(updateProjectsOnStartup || managerImpl.getProjects().length == 0) {
+ this.projectManager.refresh(new MavenUpdateRequest(workspace.getRoot().getProjects(), //
+ mavenConfiguration.isOffline() /*offline*/, false /* updateSnapshots */));
+ }
+
+ this.modelManager = new MavenModelManager(maven, projectManager, console);
+
+ this.runtimeManager = new MavenRuntimeManager(getPreferenceStore());
+ this.runtimeManager.setEmbeddedRuntime(new MavenEmbeddedRuntime(getBundleContext()));
+ this.runtimeManager.setWorkspaceRuntime(new MavenWorkspaceRuntime(projectManager));
+
+ this.configurationManager = new ProjectConfigurationManager(maven, console, projectManager, modelManager,
+ mavenMarkerManager, mavenConfiguration);
+ this.projectManager.addMavenProjectChangedListener(this.configurationManager);
+
+ //create repository registry
+ this.repositoryRegistry = new RepositoryRegistry(maven, projectManager);
+ this.maven.addSettingsChangeListener(repositoryRegistry);
+ this.projectManager.addMavenProjectChangedListener(repositoryRegistry);
+
+ //create the index manager
+ this.indexManager = new NexusIndexManager(console, projectManager, repositoryRegistry, stateLocationDir);
+ this.projectManager.addMavenProjectChangedListener(indexManager);
+ this.maven.addLocalRepositoryListener(new IndexingTransferListener(indexManager));
+ this.repositoryRegistry.addRepositoryIndexer(indexManager);
+ this.repositoryRegistry.addRepositoryDiscoverer(new IndexesExtensionReader(indexManager));
+
+ // fork repository registry update. must after index manager registered as a listener
+ this.repositoryRegistry.updateRegistry();
+
+ checkJdk();
+ }
+
+ private static ArchetypeManager newArchetypeManager(File stateLocationDir) {
+ ArchetypeManager archetypeManager = new ArchetypeManager(new File(stateLocationDir, PREFS_ARCHETYPES));
+ archetypeManager.addArchetypeCatalogFactory(new ArchetypeCatalogFactory.NexusIndexerCatalogFactory());
+ archetypeManager.addArchetypeCatalogFactory(new ArchetypeCatalogFactory.InternalCatalogFactory());
+ archetypeManager.addArchetypeCatalogFactory(new ArchetypeCatalogFactory.DefaultLocalCatalogFactory());
+ for(ArchetypeCatalogFactory archetypeCatalogFactory : ExtensionReader.readArchetypeExtensions()) {
+ archetypeManager.addArchetypeCatalogFactory(archetypeCatalogFactory);
+ }
+ return archetypeManager;
+ }
+
+ public void earlyStartup() {
+ // nothing to do here, all startup work is done in #start(BundleContext)
+ }
+
+ public PlexusContainer getPlexusContainer() {
+ return plexus;
+ }
+
+ /**
+ * This method is called when the plug-in is stopped
+ */
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+
+ this.mavenBackgroundJob.cancel();
+ try {
+ this.mavenBackgroundJob.join();
+ } catch(InterruptedException ex) {
+ // ignored
+ }
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ workspace.removeResourceChangeListener(this.mavenBackgroundJob);
+ this.mavenBackgroundJob = null;
+
+ this.projectManager.removeMavenProjectChangedListener(this.configurationManager);
+ this.projectManager.removeMavenProjectChangedListener(indexManager);
+ this.projectManager.removeMavenProjectChangedListener(repositoryRegistry);
+ this.projectManager = null;
+
+ this.plexus.dispose();
+ this.maven.disposeContainer();
+
+ this.configurationManager = null;
+
+ if(this.console != null) {
+ this.console.shutdown();
+ }
+
+ plugin = null;
+ }
+
+ private void checkJdk() {
+ if(getPreferenceStore().getBoolean(MavenPreferenceConstants.P_DISABLE_JDK_CHECK)) {
+ return;
+ }
+ // There is no tools.jar on Mac OS X
+ // http://developer.apple.com/documentation/Java/Conceptual/Java14Development/02-JavaDevTools/JavaDevTools.html
+ String osName = System.getProperty("os.name", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ if(osName.toLowerCase().indexOf("mac os") == -1) { //$NON-NLS-1$
+ String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
+ File toolsJar = new File(javaHome, "../lib/tools.jar"); //$NON-NLS-1$
+ if(!toolsJar.exists()) {
+ getConsole().logError("Eclipse is running in a JRE, but a JDK is required\n" //
+ + " Some Maven plugins may not work when importing projects or updating source folders.");
+ if(!getPreferenceStore().getBoolean(MavenPreferenceConstants.P_DISABLE_JDK_WARNING)) {
+ showJdkWarning();
+ }
+ }
+ }
+ }
+
+ private void showJdkWarning() {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ Shell shell = PlatformUI.getWorkbench().getDisplay().getActiveShell();
+ MessageDialogWithToggle dialog = new MessageDialogWithToggle(shell, //
+ Messages.MavenPlugin_error_jre_title, //
+ null, Messages.MavenPlugin_error_jre_message, MessageDialog.WARNING, //
+ new String[] {IDialogConstants.OK_LABEL}, //
+ 0, Messages.MavenPlugin_error_warn_again, false) {
+ protected Control createMessageArea(Composite composite) {
+ Image image = getImage();
+ if(image != null) {
+ imageLabel = new Label(composite, SWT.NULL);
+ image.setBackground(imageLabel.getBackground());
+ imageLabel.setImage(image);
+ GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.BEGINNING).applyTo(imageLabel);
+ }
+
+ Link link = new Link(composite, getMessageLabelStyle());
+ link.setText(message);
+ link.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ if("eclipse.ini".equals(e.text)) { //$NON-NLS-1$
+// String href = "topic=/org.eclipse.platform.doc.user/tasks/running_eclipse.htm";
+// BaseHelpSystem.getHelpDisplay().displayHelpResource(href, false);
+
+ try {
+ IWebBrowser browser = PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser();
+ // browser.openURL(new URL("http://www.eclipse.org/swt/launcher.html"));
+ browser
+ .openURL(new URL(
+ "http://help.eclipse.org/help33/index.jsp?topic=/org.eclipse.platform.doc.user/tasks/running_eclipse.htm")); //$NON-NLS-1$
+ } catch(MalformedURLException ex) {
+ MavenLogger.log("Malformed URL", ex);
+ } catch(PartInitException ex) {
+ MavenLogger.log(ex);
+ }
+ } else {
+ PreferencesUtil.createPreferenceDialogOn(getShell(),
+ "org.eclipse.jdt.debug.ui.preferences.VMPreferencePage", null, null).open(); //$NON-NLS-1$
+ }
+ }
+ });
+
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).grab(true, false)
+ .hint(convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH), SWT.DEFAULT)
+ .applyTo(link);
+
+ return composite;
+ }
+ };
+
+ dialog.setPrefStore(getPreferenceStore());
+ dialog.setPrefKey(MavenPreferenceConstants.P_DISABLE_JDK_WARNING);
+
+ dialog.open();
+
+ getPreferenceStore().setValue(MavenPreferenceConstants.P_DISABLE_JDK_WARNING, dialog.getToggleState());
+ }
+ });
+ }
+
+ /**
+ * Returns the shared instance.
+ */
+ public static MavenPlugin getDefault() {
+ return plugin;
+ }
+
+ public MavenModelManager getMavenModelManager() {
+ return this.modelManager;
+ }
+
+ public MavenProjectManager getMavenProjectManager() {
+ return this.projectManager;
+ }
+
+ public ProjectRegistryManager getMavenProjectManagerImpl() {
+ return this.managerImpl;
+ }
+
+ public IndexManager getIndexManager() {
+ return this.indexManager;
+ }
+
+ public MavenConsole getConsole() {
+ return this.console;
+ }
+
+ public MavenRuntimeManager getMavenRuntimeManager() {
+ return this.runtimeManager;
+ }
+
+ public ArchetypeManager getArchetypeManager() {
+ return this.archetypeManager;
+ }
+
+ public IMavenMarkerManager getMavenMarkerManager() {
+ return this.mavenMarkerManager;
+ }
+
+ public IMavenConfiguration getMavenConfiguration() {
+ return this.mavenConfiguration;
+ }
+
+ /**
+ * Returns an Image for the file at the given relative path.
+ */
+ public static Image getImage(String path) {
+ ImageRegistry registry = getDefault().getImageRegistry();
+ Image image = registry.get(path);
+ if(image == null) {
+ registry.put(path, imageDescriptorFromPlugin(IMavenConstants.PLUGIN_ID, path));
+ image = registry.get(path);
+ }
+ return image;
+ }
+
+ public static ImageDescriptor getImageDescriptor(String path) {
+ return imageDescriptorFromPlugin(IMavenConstants.PLUGIN_ID, path);
+ }
+
+ public BundleContext getBundleContext() {
+ return this.bundleContext;
+ }
+
+ public IProjectConfigurationManager getProjectConfigurationManager() {
+ return configurationManager;
+ }
+
+ /** for use by unit tests */
+ public ProjectRegistryRefreshJob getProjectManagerRefreshJob() {
+ return mavenBackgroundJob;
+ }
+
+ private <C> C lookup(Class<C> role) {
+ try {
+ return plexus.lookup(role);
+ } catch(ComponentLookupException ex) {
+ throw new NoSuchComponentException(ex);
+ }
+ }
+
+ private <T> T lookup(Class<T> role, String roleHint) {
+ try {
+ return plexus.lookup(role, roleHint);
+ } catch(ComponentLookupException ex) {
+ throw new NoSuchComponentException(ex);
+ }
+ }
+
+ public static String getVersion() {
+ return plugin.version;
+ }
+
+ public static String getQualifiedVersion() {
+ return plugin.qualifiedVersion;
+ }
+
+ public IRepositoryRegistry getRepositoryRegistry() {
+ return repositoryRegistry;
+ }
+
+ public Archetype getArchetype() {
+ return lookup(Archetype.class);
+ }
+
+ public ArchetypeDataSource getArchetypeDataSource(String hint) {
+ return lookup(ArchetypeDataSource.class, hint);
+ }
+
+ public ArchetypeArtifactManager getArchetypeArtifactManager() {
+ return lookup(ArchetypeArtifactManager.class);
+ }
+
+ public IndexUpdater getIndexUpdater() {
+ return lookup(IndexUpdater.class);
+ }
+
+ public WagonManager getWagonManager() {
+ return lookup(WagonManager.class);
+ }
+
+ public NexusIndexer getNexusIndexer() {
+ return lookup(NexusIndexer.class);
+ }
+
+ public ArtifactContextProducer getArtifactContextProducer() {
+ return lookup(ArtifactContextProducer.class);
+ }
+
+ public ArtifactFactory getArtifactFactory() {
+ return lookup(ArtifactFactory.class);
+ }
+
+ public ArtifactMetadataSource getArtifactMetadataSource() {
+ return lookup(ArtifactMetadataSource.class);
+ }
+
+ public ArtifactCollector getArtifactCollector() {
+ return lookup(ArtifactCollector.class);
+ }
+
+ public RepositorySystem getRepositorySystem() {
+ return lookup(RepositorySystem.class);
+ }
+
+ public MavenSession setSession(MavenSession session) {
+ LegacySupport legacy = lookup(LegacySupport.class);
+ MavenSession old = legacy.getSession();
+ legacy.setSession(session);
+ return old;
+ }
+
+ public SearchEngine getSearchEngine(IProject context) throws CoreException {
+ return new IndexSearchEngine(MavenPlugin.getDefault().getIndexManager().getIndex(context));
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/NoSuchComponentException.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/NoSuchComponentException.java
new file mode 100644
index 00000000..b79b7ddf
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/NoSuchComponentException.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core;
+
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+
+/**
+ * NoSuchComponentException
+ *
+ * @author igor
+ */
+public class NoSuchComponentException extends IllegalArgumentException {
+
+ private static final long serialVersionUID = 9184391358528175461L;
+
+ public NoSuchComponentException(ComponentLookupException ex) {
+ super(ex);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AbstractMavenMenuCreator.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AbstractMavenMenuCreator.java
new file mode 100644
index 00000000..92a431a5
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AbstractMavenMenuCreator.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IActionDelegate;
+
+import org.eclipse.m2e.core.MavenPlugin;
+
+
+/**
+ * Abstract Maven menu creator can be used to contribute custom entries to the Maven popup menu.
+ * <p>
+ * Custom items can be added to one of the standard groups {@link #NEW}, {@link #OPEN}, {@link #UPDATE}, {@link #NATURE}
+ * or {@link #IMPORT}.
+ *
+ * @see org.eclipse.m2e.m2menu extension point
+ *
+ * @author Eugene Kuleshov
+ */
+public abstract class AbstractMavenMenuCreator {
+ public static final String NEW = "new"; //$NON-NLS-1$
+ public static final String OPEN = "open"; //$NON-NLS-1$
+ public static final String UPDATE = "update"; //$NON-NLS-1$
+ public static final String NATURE = "nature"; //$NON-NLS-1$
+ public static final String IMPORT = "import"; //$NON-NLS-1$
+
+ protected IStructuredSelection selection;
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ if(selection instanceof IStructuredSelection) {
+ this.selection = (IStructuredSelection) selection;
+ }
+ }
+
+ /**
+ * Creates menu items in given menu manager.
+ */
+ public abstract void createMenu(IMenuManager mgr);
+
+ /**
+ * A helper method to create IAction instance from given IActionDelegate.
+ */
+ protected IAction getAction(IActionDelegate delegate, String id, String text) {
+ return getAction(delegate, id, text, (ImageDescriptor) null);
+ }
+
+ /**
+ * A helper method to create IAction instance from given IActionDelegate.
+ */
+ protected IAction getAction(IActionDelegate delegate, String id, String text, String image) {
+ return getAction(delegate, id, text, MavenPlugin.getImageDescriptor(image));
+ }
+
+ protected IAction getAction(IActionDelegate delegate, String id, String text, ImageDescriptor image) {
+ ActionProxy action = new ActionProxy(id, text, delegate);
+ if(image!=null) {
+ action.setImageDescriptor(image);
+ }
+ return action;
+ }
+
+ class ActionProxy extends Action {
+ private IActionDelegate action;
+
+ public ActionProxy(String id, String text, IActionDelegate action) {
+ super(text);
+ this.action = action;
+ setId(id);
+ }
+
+ public ActionProxy(String id, String text, IActionDelegate action, int style) {
+ super(text, style);
+ this.action = action;
+ setId(id);
+ }
+
+ public void run() {
+ action.selectionChanged(this, selection);
+ action.run(this);
+ }
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AddDependencyAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AddDependencyAction.java
new file mode 100644
index 00000000..316b44d5
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AddDependencyAction.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+
+import org.apache.maven.model.Dependency;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.MavenModelManager;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.ui.dialogs.MavenRepositorySearchDialog;
+
+
+public class AddDependencyAction extends MavenActionSupport implements IWorkbenchWindowActionDelegate {
+
+ public static final String ID = "org.eclipse.m2e.addDependencyAction"; //$NON-NLS-1$
+
+ public void run(IAction action) {
+ IFile file = getPomFileFromPomEditorOrViewSelection();
+
+ if(file == null) {
+ return;
+ }
+
+ MavenPlugin plugin = MavenPlugin.getDefault();
+
+ Set<ArtifactKey> artifacts = getArtifacts(file, plugin);
+ MavenRepositorySearchDialog dialog = new MavenRepositorySearchDialog(getShell(), Messages.AddDependencyAction_searchDialog_title, IIndex.SEARCH_ARTIFACT, artifacts, true);
+ if(dialog.open() == Window.OK) {
+ IndexedArtifactFile indexedArtifactFile = (IndexedArtifactFile) dialog.getFirstResult();
+ if(indexedArtifactFile != null) {
+ try {
+ MavenModelManager modelManager = plugin.getMavenModelManager();
+ Dependency dependency = indexedArtifactFile.getDependency();
+ String selectedScope = dialog.getSelectedScope();
+ dependency.setScope(selectedScope);
+ modelManager.addDependency(file, dependency);
+ } catch(Exception ex) {
+ String msg = NLS.bind(Messages.AddDependencyAction_error_msg, file);
+ MavenLogger.log(msg, ex);
+ MessageDialog.openError(Display.getCurrent().getActiveShell(), Messages.AddDependencyAction_error_title, msg);
+ }
+ }
+ }
+ }
+
+ public void dispose() {
+ }
+
+ public void init(IWorkbenchWindow window) {
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AddPluginAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AddPluginAction.java
new file mode 100644
index 00000000..5251d527
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/AddPluginAction.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.util.Collections;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.window.Window;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.MavenModelManager;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.ui.dialogs.MavenRepositorySearchDialog;
+
+
+public class AddPluginAction extends MavenActionSupport implements IWorkbenchWindowActionDelegate {
+
+ public static final String ID = "org.eclipse.m2e.addPluginAction"; //$NON-NLS-1$
+
+ public void run(IAction action) {
+ IFile file = getPomFileFromPomEditorOrViewSelection();
+
+ if(file == null) {
+ return;
+ }
+
+ MavenRepositorySearchDialog dialog = new MavenRepositorySearchDialog(getShell(), Messages.AddPluginAction_searchDialog_title, IIndex.SEARCH_PLUGIN, Collections.<ArtifactKey> emptySet());
+ if(dialog.open() == Window.OK) {
+ final IndexedArtifactFile indexedArtifactFile = (IndexedArtifactFile) dialog.getFirstResult();
+ if(indexedArtifactFile != null) {
+ try {
+ MavenModelManager modelManager = MavenPlugin.getDefault().getMavenModelManager();
+ modelManager.updateProject(file, new MavenModelManager.PluginAdder( //
+ indexedArtifactFile.group, //
+ indexedArtifactFile.artifact, //
+ indexedArtifactFile.version));
+ } catch(Exception ex) {
+ MavenLogger.log("Can't add dependency to " + file, ex);
+ }
+ }
+ }
+ }
+
+ public void dispose() {
+ }
+
+ public void init(IWorkbenchWindow window) {
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/ChangeNatureAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/ChangeNatureAction.java
new file mode 100644
index 00000000..ef074ace
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/ChangeNatureAction.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.WorkspaceJob;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.IProjectConfigurationManager;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.project.MavenUpdateRequest;
+import org.eclipse.m2e.core.project.ResolverConfiguration;
+
+
+public class ChangeNatureAction implements IObjectActionDelegate {
+
+ public static final String ID_ENABLE_WORKSPACE = "org.eclipse.m2e.enableWorkspaceResolutionAction"; //$NON-NLS-1$
+
+ public static final String ID_DISABLE_WORKSPACE = "org.eclipse.m2e.disableWorkspaceResolutionAction"; //$NON-NLS-1$
+
+ public static final int ENABLE_WORKSPACE = 1;
+
+ public static final int DISABLE_WORKSPACE = 2;
+
+ private ISelection selection;
+
+ private int option;
+
+ public ChangeNatureAction(int option) {
+ this.option = option;
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ this.selection = selection;
+ }
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ }
+
+ public void run(IAction action) {
+ if(selection instanceof IStructuredSelection) {
+ IStructuredSelection structuredSelection = (IStructuredSelection) selection;
+ Set<IProject> projects = new LinkedHashSet<IProject>();
+ for(Iterator<?> it = structuredSelection.iterator(); it.hasNext();) {
+ Object element = it.next();
+ IProject project = null;
+ if(element instanceof IProject) {
+ project = (IProject) element;
+ } else if(element instanceof IAdaptable) {
+ project = (IProject) ((IAdaptable) element).getAdapter(IProject.class);
+ }
+ if(project != null) {
+ projects.add(project);
+ }
+ }
+
+ new UpdateJob(projects, option).schedule();
+ }
+ }
+
+ static class UpdateJob extends WorkspaceJob {
+ private final Set<IProject> projects;
+ private final int option;
+
+ private final IProjectConfigurationManager importManager;
+ private final MavenProjectManager projectManager;
+ private final IMavenConfiguration mavenConfiguration;
+
+ public UpdateJob(Set<IProject> projects, int option) {
+ super(Messages.ChangeNatureAction_job_changing);
+ this.projects = projects;
+ this.option = option;
+
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ this.importManager = plugin.getProjectConfigurationManager();
+ this.projectManager = plugin.getMavenProjectManager();
+
+ this.mavenConfiguration = MavenPlugin.getDefault().getMavenConfiguration();
+ }
+
+ public IStatus runInWorkspace(IProgressMonitor monitor) {
+ MultiStatus status = null;
+ for(IProject project : projects) {
+ if (monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+
+ monitor.subTask(project.getName());
+
+ try {
+ changeNature(project, monitor);
+ } catch (CoreException ex) {
+ if (status == null) {
+ status = new MultiStatus(IMavenConstants.PLUGIN_ID, IStatus.ERROR, Messages.ChangeNatureAction_status_error, null);
+ }
+ status.add(ex.getStatus());
+ }
+ }
+
+ boolean offline = mavenConfiguration.isOffline();
+ boolean updateSnapshots = false;
+ projectManager.refresh(new MavenUpdateRequest(projects.toArray(new IProject[projects.size()]), //
+ offline, updateSnapshots));
+
+ return status != null? status: Status.OK_STATUS;
+ }
+
+ private void changeNature(final IProject project, IProgressMonitor monitor) throws CoreException {
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ MavenProjectManager projectManager = plugin.getMavenProjectManager();
+
+ final ResolverConfiguration configuration = projectManager.getResolverConfiguration(project);
+
+ boolean updateSourceFolders = false;
+
+ switch(option) {
+ case ENABLE_WORKSPACE:
+ configuration.setResolveWorkspaceProjects(true);
+ break;
+ case DISABLE_WORKSPACE:
+ configuration.setResolveWorkspaceProjects(false);
+ break;
+ }
+
+ projectManager.setResolverConfiguration(project, configuration);
+
+ if (updateSourceFolders) {
+ importManager.updateProjectConfiguration(project, configuration, monitor);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/CheckoutAsMavenAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/CheckoutAsMavenAction.java
new file mode 100644
index 00000000..9431826e
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/CheckoutAsMavenAction.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.util.Iterator;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.scm.ScmUrl;
+import org.eclipse.m2e.core.wizards.MavenCheckoutWizard;
+
+
+/**
+ * Checkout as Maven project action
+ *
+ * @author @author Eugene Kuleshov
+ */
+public class CheckoutAsMavenAction implements IObjectActionDelegate {
+
+ private IStructuredSelection selection;
+ private IWorkbenchPart targetPart;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.actions.ActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
+ */
+ public void selectionChanged(IAction action, ISelection selection) {
+ if (selection instanceof IStructuredSelection) {
+ this.selection = (IStructuredSelection) selection;
+ }
+ }
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ this.targetPart = targetPart;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.actions.ActionDelegate#run(org.eclipse.jface.action.IAction)
+ */
+ public void run(IAction action) {
+ ScmUrl[] urls = null;
+ if(selection != null) {
+ urls = new ScmUrl[selection.size()];
+ int i = 0;
+ for(Iterator<?> it = selection.iterator(); it.hasNext();) {
+ urls[i++] = (ScmUrl) it.next();
+ }
+ }
+
+ MavenCheckoutWizard wizard = new MavenCheckoutWizard(urls);
+ WizardDialog dialog = new WizardDialog(getShell(), wizard);
+ dialog.open();
+ }
+
+ protected Shell getShell() {
+ Shell shell = null;
+ if(targetPart != null) {
+ shell = targetPart.getSite().getShell();
+ }
+ if(shell != null) {
+ return shell;
+ }
+
+ IWorkbench workbench = MavenPlugin.getDefault().getWorkbench();
+ if(workbench == null) {
+ return null;
+ }
+
+ IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+ return window == null ? null : window.getShell();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/DisableNatureAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/DisableNatureAction.java
new file mode 100644
index 00000000..7ae99170
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/DisableNatureAction.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.util.Iterator;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+
+
+public class DisableNatureAction implements IObjectActionDelegate {
+ public static final String ID = "org.eclipse.m2e.disableAction"; //$NON-NLS-1$
+
+ private ISelection selection;
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+ */
+ public void run(IAction action) {
+ if(selection instanceof IStructuredSelection) {
+ IStructuredSelection structuredSelection = (IStructuredSelection) selection;
+ for(Iterator<?> it = structuredSelection.iterator(); it.hasNext();) {
+ Object element = it.next();
+ IProject project = null;
+ if(element instanceof IProject) {
+ project = (IProject) element;
+ } else if(element instanceof IAdaptable) {
+ project = (IProject) ((IAdaptable) element).getAdapter(IProject.class);
+ }
+ if(project != null) {
+ MavenPlugin plugin = MavenPlugin.getDefault();
+
+ try {
+ plugin.getProjectConfigurationManager().disableMavenNature(project, new NullProgressMonitor());
+
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction,
+ * org.eclipse.jface.viewers.ISelection)
+ */
+ public void selectionChanged(IAction action, ISelection selection) {
+ this.selection = selection;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction,
+ * org.eclipse.ui.IWorkbenchPart)
+ */
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/EnableNatureAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/EnableNatureAction.java
new file mode 100644
index 00000000..2dec17c2
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/EnableNatureAction.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.util.Iterator;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPart;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.IProjectConfigurationManager;
+import org.eclipse.m2e.core.project.ResolverConfiguration;
+import org.eclipse.m2e.core.wizards.MavenPomWizard;
+
+
+public class EnableNatureAction implements IObjectActionDelegate, IExecutableExtension {
+
+ public static final String ID = "org.eclipse.m2e.enableNatureAction"; //$NON-NLS-1$
+
+ static final String ID_WORKSPACE = "org.eclipse.m2e.enableWorkspaceResolutionAction"; //$NON-NLS-1$
+
+ static final String ID_MODULES = "org.eclipse.m2e.enableModulesAction"; //$NON-NLS-1$
+
+ private boolean workspaceProjects = true;
+
+ private ISelection selection;
+
+ public EnableNatureAction() {
+ }
+
+ public EnableNatureAction(String option) {
+ setInitializationData(null, null, option);
+ }
+
+ public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
+ if(IMavenConstants.NO_WORKSPACE_PROJECTS.equals(data)) {
+ this.workspaceProjects = false;
+ }
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ this.selection = selection;
+ }
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ }
+
+ public void run(IAction action) {
+ if(selection instanceof IStructuredSelection) {
+ IStructuredSelection structuredSelection = (IStructuredSelection) selection;
+ for(Iterator<?> it = structuredSelection.iterator(); it.hasNext();) {
+ Object element = it.next();
+ IProject project = null;
+ if(element instanceof IProject) {
+ project = (IProject) element;
+ } else if(element instanceof IAdaptable) {
+ project = (IProject) ((IAdaptable) element).getAdapter(IProject.class);
+ }
+ if(project != null) {
+ enableNature(project, structuredSelection.size() == 1);
+ }
+ }
+ }
+ }
+
+ private void enableNature(final IProject project, boolean isSingle) {
+ final MavenPlugin plugin = MavenPlugin.getDefault();
+ IFile pom = project.getFile(IMavenConstants.POM_FILE_NAME);
+ if(isSingle && !pom.exists()) {
+ // XXX move into AbstractProjectConfigurator and use Eclipse project settings
+ IWorkbench workbench = plugin.getWorkbench();
+
+ MavenPomWizard wizard = new MavenPomWizard();
+ wizard.init(workbench, (IStructuredSelection) selection);
+
+ Shell shell = workbench.getActiveWorkbenchWindow().getShell();
+ WizardDialog wizardDialog = new WizardDialog(shell, wizard);
+ wizardDialog.create();
+ wizardDialog.getShell().setText(Messages.EnableNatureAction_wizard_shell);
+ if(wizardDialog.open() == Window.CANCEL) {
+ return;
+ }
+ }
+ Job job = new Job(Messages.EnableNatureAction_job_enable) {
+
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ ResolverConfiguration configuration = new ResolverConfiguration();
+ configuration.setResolveWorkspaceProjects(workspaceProjects);
+ configuration.setActiveProfiles(""); //$NON-NLS-1$
+
+ boolean hasMavenNature = project.hasNature(IMavenConstants.NATURE_ID);
+
+ IProjectConfigurationManager configurationManager = plugin.getProjectConfigurationManager();
+
+ configurationManager.enableMavenNature(project, configuration, new NullProgressMonitor());
+
+ if(!hasMavenNature) {
+ configurationManager.updateProjectConfiguration(project, configuration, monitor);
+ }
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.schedule();
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MaterializeAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MaterializeAction.java
new file mode 100644
index 00000000..fee02f4f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MaterializeAction.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PlatformUI;
+
+import org.apache.maven.model.Dependency;
+
+import org.eclipse.m2e.core.wizards.MavenMaterializePomWizard;
+
+
+public class MaterializeAction implements IObjectActionDelegate {
+
+ public static final String ID = "org.eclipse.m2e.materializeAction"; //$NON-NLS-1$
+
+ private IStructuredSelection selection;
+
+ public void run(IAction action) {
+ MavenMaterializePomWizard wizard = new MavenMaterializePomWizard();
+ wizard.init(PlatformUI.getWorkbench(), selection);
+
+ Dependency[] dependencies = wizard.getDependencies();
+ if(dependencies!=null && dependencies.length>0) {
+ WizardDialog dialog = new WizardDialog(Display.getCurrent().getActiveShell(), wizard);
+ dialog.open();
+ } else {
+ // TODO show info dialog
+ }
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ if(selection instanceof IStructuredSelection) {
+ this.selection = (IStructuredSelection) selection;
+ } else {
+ this.selection = null;
+ }
+ }
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenActionSupport.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenActionSupport.java
new file mode 100644
index 00000000..9e9ff69c
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenActionSupport.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.ArtifactRef;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+
+/**
+ *
+ * MavenActionSupport
+ *
+ * @author Jason van Zyl
+ */
+public abstract class MavenActionSupport implements IObjectActionDelegate {
+ protected IStructuredSelection selection;
+
+ protected IWorkbenchPart targetPart;
+
+ protected Set<ArtifactKey> getArtifacts(IFile file, MavenPlugin plugin) {
+ try {
+ MavenProjectManager projectManager = plugin.getMavenProjectManager();
+ IMavenProjectFacade projectFacade = projectManager.create(file, true, new NullProgressMonitor());
+ if(projectFacade != null) {
+ return ArtifactRef.toArtifactKey(projectFacade.getMavenProjectArtifacts());
+ }
+ } catch(Exception ex) {
+ String msg = "Can't read Maven project";
+ MavenLogger.log(msg, ex);
+ plugin.getConsole().logError(msg + "; " + ex.toString());
+ }
+ return Collections.emptySet();
+ }
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ this.targetPart = targetPart;
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ if(selection instanceof IStructuredSelection) {
+ this.selection = (IStructuredSelection) selection;
+ }
+ }
+
+ protected Shell getShell() {
+ Shell shell = null;
+ if(targetPart != null) {
+ shell = targetPart.getSite().getShell();
+ }
+ if(shell != null) {
+ return shell;
+ }
+
+ IWorkbench workbench = MavenPlugin.getDefault().getWorkbench();
+ if(workbench == null) {
+ return null;
+ }
+
+ IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+ return window == null ? null : window.getShell();
+ }
+
+ protected IFile getPomFileFromPomEditorOrViewSelection() {
+ IFile file = null;
+ //
+ // If I am in the POM editor I want to get hold of the IFile that is currently in the buffer
+ //
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+
+ if(window != null) {
+ IWorkbenchPage page = window.getActivePage();
+ if(page != null) {
+ IEditorPart editor = page.getActiveEditor();
+ if(editor != null) {
+ IEditorInput input = editor.getEditorInput();
+ if(input instanceof IFileEditorInput) {
+ IFileEditorInput fileInput = (IFileEditorInput) input;
+ file = fileInput.getFile();
+ if(file.getName().equals(IMavenConstants.POM_FILE_NAME)) {
+ return file;
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Otherwise we will assume a pom.xml file or IProject is being selected in the
+ // package explorer and we'll get the IFile from that. Otherwise we'll bail.
+ //
+ Object o = selection.iterator().next();
+
+ if(o instanceof IProject) {
+ file = ((IProject) o).getFile(IMavenConstants.POM_FILE_NAME);
+ } else if(o instanceof IFile) {
+ file = (IFile) o;
+ } else {
+ file = null;
+ }
+
+ return file;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenConsoleRemoveAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenConsoleRemoveAction.java
new file mode 100644
index 00000000..92aa714d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenConsoleRemoveAction.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import org.eclipse.jface.action.Action;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.internal.Messages;
+
+public class MavenConsoleRemoveAction extends Action {
+
+ public MavenConsoleRemoveAction() {
+ setToolTipText(Messages.MavenConsoleRemoveAction_tooltip);
+ setImageDescriptor(MavenImages.CLOSE);
+ }
+
+ public void run() {
+ MavenPlugin.getDefault().getConsole().closeConsole();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenDebugOutputAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenDebugOutputAction.java
new file mode 100644
index 00000000..c36e5357
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenDebugOutputAction.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
+
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class MavenDebugOutputAction extends Action {
+
+ private IPropertyChangeListener listener = new IPropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ if(MavenPreferenceConstants.P_DEBUG_OUTPUT.equals(event.getProperty())) {
+ setChecked(isDebug());
+ }
+ }
+ };
+
+ public MavenDebugOutputAction() {
+ setToolTipText(Messages.MavenDebugOutputAction_0);
+ setImageDescriptor(MavenImages.DEBUG);
+
+ getPreferenceStore().addPropertyChangeListener(listener);
+ setChecked(isDebug());
+ }
+
+ public void run() {
+ getPreferenceStore().setValue(MavenPreferenceConstants.P_DEBUG_OUTPUT, isChecked());
+ }
+
+ public void dispose() {
+ getPreferenceStore().removePropertyChangeListener(listener);
+ }
+
+ IPreferenceStore getPreferenceStore() {
+ return MavenPlugin.getDefault().getPreferenceStore();
+ }
+
+ boolean isDebug() {
+ return getPreferenceStore().getBoolean(MavenPreferenceConstants.P_DEBUG_OUTPUT);
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenMenuAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenMenuAction.java
new file mode 100644
index 00000000..6c67de47
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenMenuAction.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.events.MenuAdapter;
+import org.eclipse.swt.events.MenuEvent;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.actions.DefaultMavenMenuCreator;
+
+
+/**
+ * Maven menu action
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenMenuAction implements IObjectActionDelegate, IMenuCreator {
+
+ private static final String EXTENSION_MENU_ITEMS = IMavenConstants.PLUGIN_ID + ".m2menu"; //$NON-NLS-1$
+
+ boolean fillMenu;
+
+ IAction delegateAction;
+
+ List<AbstractMavenMenuCreator> creators = null;
+
+ // IObjectActionDelegate
+
+ public void run(IAction action) {
+ }
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ if(selection instanceof IStructuredSelection) {
+ // this.selection = (IStructuredSelection) selection;
+ this.fillMenu = true;
+
+ if(delegateAction != action) {
+ delegateAction = action;
+ delegateAction.setMenuCreator(this);
+ }
+
+ action.setEnabled(!selection.isEmpty());
+
+ for(AbstractMavenMenuCreator creator : getCreators()) {
+ creator.selectionChanged(action, selection);
+ }
+ }
+ }
+
+ // IMenuCreator
+
+ public void dispose() {
+ }
+
+ public Menu getMenu(Control parent) {
+ return null;
+ }
+
+ public Menu getMenu(Menu parent) {
+ Menu menu = new Menu(parent);
+
+ /**
+ * Add listener to re-populate the menu each time it is shown because MenuManager.update(boolean, boolean) doesn't
+ * dispose pull-down ActionContribution items for each popup menu.
+ */
+ menu.addMenuListener(new MenuAdapter() {
+ public void menuShown(MenuEvent e) {
+ if(fillMenu) {
+ Menu m = (Menu) e.widget;
+
+ for(MenuItem item : m.getItems()) {
+ item.dispose();
+ }
+
+ IMenuManager mgr = new MenuManager("#maven"); //$NON-NLS-1$
+ mgr.add(new GroupMarker(AbstractMavenMenuCreator.NEW));
+ mgr.insertAfter(AbstractMavenMenuCreator.NEW, new GroupMarker(AbstractMavenMenuCreator.UPDATE));
+ mgr.insertAfter(AbstractMavenMenuCreator.UPDATE, new GroupMarker(AbstractMavenMenuCreator.OPEN));
+ mgr.insertAfter(AbstractMavenMenuCreator.OPEN, new GroupMarker(AbstractMavenMenuCreator.NATURE));
+ mgr.insertAfter(AbstractMavenMenuCreator.NATURE, new GroupMarker(AbstractMavenMenuCreator.IMPORT));
+
+ for(AbstractMavenMenuCreator creator : getCreators()) {
+ creator.createMenu(mgr);
+ }
+
+ for(IContributionItem item : mgr.getItems()) {
+ item.fill(m, -1);
+ }
+
+ fillMenu = false;
+ }
+ }
+ });
+
+ return menu;
+ }
+
+ List<AbstractMavenMenuCreator> getCreators() {
+ if(creators == null) {
+ creators = new ArrayList<AbstractMavenMenuCreator>();
+ creators.add(new DefaultMavenMenuCreator());
+
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint extensionPoint = registry.getExtensionPoint(EXTENSION_MENU_ITEMS);
+ if(extensionPoint!=null) {
+ for(IExtension extension : extensionPoint.getExtensions()) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for(IConfigurationElement element : elements) {
+ try {
+ AbstractMavenMenuCreator creator = (AbstractMavenMenuCreator) element.createExecutableExtension("class"); //$NON-NLS-1$
+ creators.add(creator);
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+ }
+ return creators;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenPropertyTester.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenPropertyTester.java
new file mode 100644
index 00000000..9bf3586f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/MavenPropertyTester.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IAdaptable;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+
+/**
+ * Helper IPropertyTester implementation to check if receiver can be launched with Maven.
+ * E.g. it is pom.xml file of folder or project that has pom.xml.
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenPropertyTester extends PropertyTester {
+
+ public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
+ IAdaptable adaptable = (IAdaptable) receiver;
+
+ IProject projectAdapter = (IProject) adaptable.getAdapter(IProject.class);
+ if(projectAdapter!=null) {
+ return projectAdapter.getFile(IMavenConstants.POM_FILE_NAME).exists();
+ }
+
+ IFolder folderAdapter = (IFolder) adaptable.getAdapter(IFolder.class);
+ if(folderAdapter!=null) {
+ return folderAdapter.getFile(IMavenConstants.POM_FILE_NAME).exists();
+ }
+
+ IFile fileAdapter = (IFile) adaptable.getAdapter(IFile.class);
+ if(fileAdapter!=null) {
+ return fileAdapter.exists() && IMavenConstants.POM_FILE_NAME.equals(fileAdapter.getName());
+ }
+
+ return false;
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/ModuleProjectWizardAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/ModuleProjectWizardAction.java
new file mode 100644
index 00000000..ed7223c9
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/ModuleProjectWizardAction.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.m2e.core.wizards.MavenModuleWizard;
+
+/**
+ * A module project wizard action.
+ */
+public class ModuleProjectWizardAction implements IObjectActionDelegate {
+
+ /** action id */
+ public static final String ID =
+ "org.eclipse.m2e.actions.moduleProjectWizardAction"; //$NON-NLS-1$
+
+ /** the current selection */
+ private IStructuredSelection selection;
+
+ /** parent shell */
+ private Shell parent;
+
+ /** Runs the action. */
+ public void run( IAction action ) {
+ MavenModuleWizard wizard = new MavenModuleWizard();
+ wizard.init( PlatformUI.getWorkbench(), selection );
+ WizardDialog dialog = new WizardDialog( parent, wizard );
+ dialog.open();
+ }
+
+
+ /** Sets the active workbench part. */
+ public void setActivePart( IAction action, IWorkbenchPart part ) {
+ parent = part.getSite().getShell();
+ }
+
+
+ /** Handles the selection change */
+ public void selectionChanged( IAction action, ISelection selection ) {
+ if( selection instanceof IStructuredSelection ) {
+ this.selection = ( IStructuredSelection ) selection;
+ }
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenMavenConsoleAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenMavenConsoleAction.java
new file mode 100644
index 00000000..47b10f71
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenMavenConsoleAction.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import org.eclipse.jface.action.Action;
+
+import org.eclipse.m2e.core.MavenPlugin;
+
+/**
+ * Open Maven Console Action
+ *
+ * @author Eugene Kuleshov
+ */
+public class OpenMavenConsoleAction extends Action {
+
+ public void run() {
+ MavenPlugin.getDefault().getConsole().showConsole();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenPomAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenPomAction.java
new file mode 100644
index 00000000..700b6c54
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenPomAction.java
@@ -0,0 +1,404 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.content.IContentTypeManager;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.IPathEditorInput;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.IStorageEditorInput;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionDelegate;
+import org.eclipse.ui.part.FileEditorInput;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.ui.dialogs.MavenRepositorySearchDialog;
+
+
+/**
+ * Open POM Action
+ *
+ * @author Eugene Kuleshov
+ */
+public class OpenPomAction extends ActionDelegate implements IWorkbenchWindowActionDelegate, IExecutableExtension {
+
+ public static final String ID = "org.eclipse.m2e.openPomAction"; //$NON-NLS-1$
+
+ String type = IIndex.SEARCH_ARTIFACT;
+
+ private IStructuredSelection selection;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#init(org.eclipse.ui.IWorkbenchWindow)
+ */
+ public void init(IWorkbenchWindow window) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object)
+ */
+ public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
+ if("plugins".equals(data)) { //$NON-NLS-1$
+ this.type = IIndex.SEARCH_PACKAGING;
+ } else {
+ this.type = IIndex.SEARCH_ARTIFACT;
+ }
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ if(selection instanceof IStructuredSelection) {
+ this.selection = (IStructuredSelection) selection;
+ } else {
+ this.selection = null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.actions.ActionDelegate#run(org.eclipse.jface.action.IAction)
+ */
+ public void run(IAction action) {
+ if(selection != null) {
+ Object element = this.selection.getFirstElement();
+ if(IIndex.SEARCH_ARTIFACT.equals(type) && element != null) {
+ try {
+ final ArtifactKey ak = SelectionUtil.getArtifactKey(element);
+ if(ak != null) {
+ new Job(Messages.OpenPomAction_job_opening) {
+ protected IStatus run(IProgressMonitor monitor) {
+ openEditor(ak.getGroupId(), ak.getArtifactId(), ak.getVersion(), monitor);
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ return;
+ }
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ MessageDialog.openInformation(Display.getDefault().getActiveShell(), //
+ Messages.OpenPomAction_open_error_title, Messages.OpenPomAction_open_error_message);
+ }
+ });
+ }
+ }
+ }
+
+ String title = Messages.OpenPomAction_title_pom;
+
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ MavenRepositorySearchDialog dialog = new MavenRepositorySearchDialog(shell, title, type, Collections
+ .<ArtifactKey> emptySet());
+ if(dialog.open() == Window.OK) {
+ final IndexedArtifactFile iaf = (IndexedArtifactFile) dialog.getFirstResult();
+ new Job(Messages.OpenPomAction_job_opening) {
+ protected IStatus run(IProgressMonitor monitor) {
+ if(iaf != null) {
+ openEditor(iaf.group, iaf.artifact, iaf.version, monitor);
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+ }
+
+ public static void openEditor(IndexedArtifact ia, IndexedArtifactFile f, IProgressMonitor monitor) {
+ if(f == null || ia.getClassname() == null || ia.getPackageName() == null) {
+ return;
+ }
+
+ String groupId = f.getDependency().getGroupId();
+ String artifactId = f.getDependency().getArtifactId();
+ String version = f.getDependency().getVersion();
+
+ String name = ia.getClassname();
+ String fileName = ia.getPackageName().replace('.', '/') + "/" + ia.getClassname() + ".java"; //$NON-NLS-1$ //$NON-NLS-2$
+ String tooltip = groupId + ":" + artifactId + ":" + version + "/" + fileName; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ try {
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+
+ List<ArtifactRepository> artifactRepositories = maven.getArtifactRepositories();
+
+ Artifact artifact = maven.resolve(groupId, artifactId, version, "java-source", "sources", artifactRepositories, //$NON-NLS-1$ //$NON-NLS-2$
+ monitor);
+
+ final File file = artifact.getFile();
+ if(file == null) {
+ openDialog(NLS.bind(Messages.OpenPomAction_error_download_source, tooltip));
+ return;
+ }
+
+ // that won't work if source archive have subfolders before actual source tree
+ String url = "jar:" + file.toURL().toString() + "!/" + fileName; //$NON-NLS-1$ //$NON-NLS-2$
+ InputStream is = new URL(url).openStream();
+ byte[] buff = readStream(is);
+
+ openEditor(new MavenPathStorageEditorInput(name + ".java", tooltip, url, buff), name + ".java"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ } catch(IOException ex) {
+ String msg = NLS.bind(Messages.OpenPomAction_error_open_editor, name);
+ MavenLogger.log(msg, ex);
+ openDialog(msg + "\n" + ex.toString()); //$NON-NLS-1$
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ openDialog(ex.getMessage() + "\n" + ex.toString()); //$NON-NLS-1$
+ }
+ }
+
+ public static IEditorPart openEditor(String groupId, String artifactId, String version, IProgressMonitor monitor) {
+ if(groupId.length() > 0 && artifactId.length() > 0) {
+ final String name = groupId + ":" + artifactId + ":" + version + ".pom"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ try {
+ MavenPlugin plugin = MavenPlugin.getDefault();
+
+ MavenProjectManager projectManager = plugin.getMavenProjectManager();
+ IMavenProjectFacade projectFacade = projectManager.getMavenProject(groupId, artifactId, version);
+ if(projectFacade != null) {
+ final IFile pomFile = projectFacade.getPom();
+ return openEditor(new FileEditorInput(pomFile), name);
+ }
+
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+
+ List<ArtifactRepository> artifactRepositories = maven.getArtifactRepositories();
+
+ Artifact artifact = maven.resolve(groupId, artifactId, version, "pom", null, artifactRepositories, monitor); //$NON-NLS-1$
+
+ File file = artifact.getFile();
+ if(file != null) {
+ return openEditor(new MavenPathStorageEditorInput(name, name, file.getAbsolutePath(),
+ readStream(new FileInputStream(file))), name);
+ }
+
+ openDialog(NLS.bind(Messages.OpenPomAction_error_download, name));
+
+ } catch(IOException ex) {
+ String msg = NLS.bind(Messages.OpenPomAction_error_open_pom, name);
+ MavenLogger.log(msg, ex);
+ openDialog(msg + "\n" + ex.toString()); //$NON-NLS-1$
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ openDialog(ex.getMessage() + "\n" + ex.toString()); //$NON-NLS-1$
+ }
+ }
+
+ return null;
+ }
+
+ public static IEditorPart openEditor(final IEditorInput editorInput, final String name) {
+ final IEditorPart[] part = new IEditorPart[1];
+ PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
+ public void run() {
+ IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
+ IContentType contentType = contentTypeManager.findContentTypeFor(name);
+ IEditorRegistry editorRegistry = PlatformUI.getWorkbench().getEditorRegistry();
+ IEditorDescriptor editor = editorRegistry.getDefaultEditor(name, contentType);
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if(window != null) {
+ IWorkbenchPage page = window.getActivePage();
+ if(page != null) {
+ try {
+ part[0] = page.openEditor(editorInput, editor.getId());
+ } catch(PartInitException ex) {
+ MessageDialog.openInformation(Display.getDefault().getActiveShell(), //
+ Messages.OpenPomAction_open_title, NLS.bind(Messages.OpenPomAction_33, editorInput.getName(), ex.toString())); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ });
+ return part[0];
+ }
+
+ private static void openDialog(final String msg) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ MessageDialog.openInformation(Display.getDefault().getActiveShell(), //
+ Messages.OpenPomAction_open_title, msg);
+ }
+ });
+ }
+
+ private static byte[] readStream(InputStream is) throws IOException {
+ byte[] b = new byte[is.available()];
+ int len = 0;
+ while(true) {
+ int n = is.read(b, len, b.length - len);
+ if(n == -1) {
+ if(len < b.length) {
+ byte[] c = new byte[len];
+ System.arraycopy(b, 0, c, 0, len);
+ b = c;
+ }
+ return b;
+ }
+ len += n;
+ if(len == b.length) {
+ byte[] c = new byte[b.length + 1000];
+ System.arraycopy(b, 0, c, 0, len);
+ b = c;
+ }
+ }
+ }
+
+ /**
+ * Storage editor input implementation for Maven poms
+ */
+ public static class MavenStorageEditorInput implements IStorageEditorInput {
+
+ private final String name;
+
+ private final String path;
+
+ private final String tooltip;
+
+ private final byte[] content;
+
+ public MavenStorageEditorInput(String name, String tooltip, String path, byte[] content) {
+ this.name = name;
+ this.path = path;
+ this.tooltip = tooltip;
+ this.content = content;
+ }
+
+ // IStorageEditorInput
+
+ public boolean exists() {
+ return true;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getToolTipText() {
+ return this.tooltip;
+ }
+
+ public IStorage getStorage() {
+ return new MavenStorage(name, path, content);
+ }
+
+ public ImageDescriptor getImageDescriptor() {
+ return null;
+ }
+
+ public IPersistableElement getPersistable() {
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ return null;
+ }
+
+ // IPathEditorInput
+
+ public IPath getPath() {
+ return new Path(path);
+ }
+
+ }
+
+ public static class MavenPathStorageEditorInput extends MavenStorageEditorInput implements IPathEditorInput {
+ public MavenPathStorageEditorInput(String name, String tooltip, String path, byte[] content) {
+ super(name, tooltip, path, content);
+ }
+ }
+
+ private static class MavenStorage implements IStorage {
+ private String name;
+
+ private final String path;
+
+ private final byte[] content;
+
+ public MavenStorage(String name, String path, byte[] content) {
+ this.name = name;
+ this.path = path;
+ this.content = content;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public IPath getFullPath() {
+ return path == null ? null : new Path(path);
+ }
+
+ public InputStream getContents() {
+ return new ByteArrayInputStream(content);
+ }
+
+ public boolean isReadOnly() {
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ return null;
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenUrlAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenUrlAction.java
new file mode 100644
index 00000000..2b81ec4b
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/OpenUrlAction.java
@@ -0,0 +1,230 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionDelegate;
+import org.eclipse.ui.browser.IWebBrowser;
+import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.model.CiManagement;
+import org.apache.maven.model.IssueManagement;
+import org.apache.maven.model.Scm;
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+
+/**
+ * Open Url Action
+ *
+ * @author Eugene Kuleshov
+ */
+public class OpenUrlAction extends ActionDelegate implements IWorkbenchWindowActionDelegate, IExecutableExtension {
+
+ public static final String ID_PROJECT = "org.eclipse.m2e.openProjectPage"; //$NON-NLS-1$
+
+ public static final String ID_ISSUES = "org.eclipse.m2e.openIssuesPage"; //$NON-NLS-1$
+
+ public static final String ID_SCM = "org.eclipse.m2e.openScmPage"; //$NON-NLS-1$
+
+ public static final String ID_CI = "org.eclipse.m2e.openCiPage"; //$NON-NLS-1$
+
+ String actionId;
+
+ private IStructuredSelection selection;
+
+ public OpenUrlAction() {
+ }
+
+ public OpenUrlAction(String id) {
+ this.actionId = id;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
+ */
+ public void selectionChanged(IAction action, ISelection selection) {
+ if(selection instanceof IStructuredSelection) {
+ this.selection = (IStructuredSelection) selection;
+ } else {
+ this.selection = null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+ */
+ public void run(IAction action) {
+ if(selection != null) {
+ try {
+ Object element = this.selection.getFirstElement();
+ final ArtifactKey a = SelectionUtil.getArtifactKey(element);
+ if(a != null) {
+ new Job(Messages.OpenUrlAction_job_browser) {
+ protected IStatus run(IProgressMonitor monitor) {
+ openBrowser(actionId, a.getGroupId(), a.getArtifactId(), a.getVersion(), monitor);
+ return Status.OK_STATUS;
+ }
+
+ }.schedule();
+ return;
+ }
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ MessageDialog.openInformation(Display.getDefault().getActiveShell(), //
+ Messages.OpenUrlAction_open_url_title, Messages.OpenUrlAction_open_url_message);
+ }
+ });
+ }
+ }
+ }
+
+ public static void openBrowser(String actionId, String groupId, String artifactId, String version, IProgressMonitor monitor) {
+ try {
+ MavenProject mavenProject = getMavenProject(groupId, artifactId, version, monitor);
+ final String url = getUrl(actionId, mavenProject);
+ if(url!=null) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ try {
+ IWorkbenchBrowserSupport browserSupport = PlatformUI.getWorkbench().getBrowserSupport();
+ IWebBrowser browser = browserSupport.createBrowser(IWorkbenchBrowserSupport.NAVIGATION_BAR
+ | IWorkbenchBrowserSupport.LOCATION_BAR, url, url, url);
+ browser.openURL(new URL(url));
+ } catch(PartInitException ex) {
+ MavenLogger.log(ex);
+ } catch(MalformedURLException ex) {
+ MavenLogger.log("Malformed url " + url, ex);
+ }
+ }
+ });
+ }
+ } catch(Exception ex) {
+ MavenLogger.log("Can't open URL", ex);
+ }
+ }
+
+ private static String getUrl(String actionId, MavenProject mavenProject) {
+ String url = null;
+ if(ID_PROJECT.equals(actionId)) {
+ url = mavenProject.getUrl();
+ if(url == null) {
+ openDialog(Messages.OpenUrlAction_error_no_url);
+ }
+ } else if(ID_ISSUES.equals(actionId)) {
+ IssueManagement issueManagement = mavenProject.getIssueManagement();
+ if(issueManagement != null) {
+ url = issueManagement.getUrl();
+ }
+ if(url == null) {
+ openDialog(Messages.OpenUrlAction_error_no_issues);
+ }
+ } else if(ID_SCM.equals(actionId)) {
+ Scm scm = mavenProject.getScm();
+ if(scm != null) {
+ url = scm.getUrl();
+ }
+ if(url == null) {
+ openDialog(Messages.OpenUrlAction_error_no_scm);
+ }
+ } else if(ID_CI.equals(actionId)) {
+ CiManagement ciManagement = mavenProject.getCiManagement();
+ if(ciManagement != null) {
+ url = ciManagement.getUrl();
+ }
+ if(url == null) {
+ openDialog(Messages.OpenUrlAction_error_no_ci);
+ }
+ }
+ return url;
+ }
+
+ private static MavenProject getMavenProject(String groupId, String artifactId, String version, IProgressMonitor monitor) throws Exception {
+ String name = groupId + ":" + artifactId + ":" + version;
+
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+
+ IMavenProjectFacade projectFacade = plugin.getMavenProjectManager().getMavenProject(groupId, artifactId, version);
+ if(projectFacade != null) {
+ return projectFacade.getMavenProject(monitor);
+ }
+
+ List<ArtifactRepository> artifactRepositories = maven.getArtifactRepositories();
+
+ Artifact a = maven.resolve(groupId, artifactId, version, "pom", null, artifactRepositories, monitor); //$NON-NLS-1$
+
+ File pomFile = a.getFile();
+ if(pomFile == null) {
+ openDialog(NLS.bind(Messages.OpenUrlAction_error_open, name));
+ return null;
+ }
+
+ return maven.readProject(pomFile, monitor);
+ }
+
+ private static void openDialog(final String msg) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ MessageDialog.openInformation(Display.getDefault().getActiveShell(), //
+ Messages.OpenUrlAction_browser_title, msg);
+ }
+ });
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#init(org.eclipse.ui.IWorkbenchWindow)
+ */
+ public void init(IWorkbenchWindow window) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object)
+ */
+ public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
+ if(data != null) {
+ actionId = (String) data;
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/RefreshMavenModelsAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/RefreshMavenModelsAction.java
new file mode 100644
index 00000000..5c2fa7fa
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/RefreshMavenModelsAction.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.IWorkingSet;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.project.MavenUpdateRequest;
+
+
+public class RefreshMavenModelsAction implements IWorkbenchWindowActionDelegate, IExecutableExtension {
+
+ public static final String ID = "org.eclipse.m2e.refreshMavenModelsAction"; //$NON-NLS-1$
+
+ public static final String ID_SNAPSHOTS = "org.eclipse.m2e.refreshMavenSnapshotsAction"; //$NON-NLS-1$
+
+ private boolean updateSnapshots = false;
+
+ private boolean offline = false; // should respect global settings
+
+ private IStructuredSelection selection;
+
+ public RefreshMavenModelsAction() {
+ }
+
+ public RefreshMavenModelsAction(boolean updateSnapshots) {
+ this.updateSnapshots = updateSnapshots;
+ }
+
+ // IExecutableExtension
+
+ public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
+ if("snapshots".equals(data)) { //$NON-NLS-1$
+ this.updateSnapshots = true;
+ }
+ }
+
+ // IWorkbenchWindowActionDelegate
+
+ public void run(IAction action) {
+ MavenProjectManager projectManager = MavenPlugin.getDefault().getMavenProjectManager();
+ projectManager.refresh(new MavenUpdateRequest(getProjects(), offline, updateSnapshots));
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ if(selection instanceof IStructuredSelection) {
+ this.selection = (IStructuredSelection) selection;
+ } else {
+ this.selection = null;
+ }
+ }
+
+ public void dispose() {
+ }
+
+ public void init(IWorkbenchWindow window) {
+ }
+
+ private IProject[] getProjects() {
+ ArrayList<IProject> projectList = new ArrayList<IProject>();
+ if(selection != null) {
+ for(Iterator<?> it = selection.iterator(); it.hasNext();) {
+ Object o = it.next();
+ if(o instanceof IProject) {
+ projectList.add((IProject) o);
+ } else if(o instanceof IWorkingSet) {
+ IWorkingSet workingSet = (IWorkingSet) o;
+ for(IAdaptable adaptable : workingSet.getElements()) {
+ IProject project = (IProject) adaptable.getAdapter(IProject.class);
+ try {
+ if(project != null && project.isAccessible() && project.hasNature(IMavenConstants.NATURE_ID)) {
+ projectList.add(project);
+ }
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+ }
+ if(projectList.isEmpty()) {
+ return ResourcesPlugin.getWorkspace().getRoot().getProjects();
+ }
+ return projectList.toArray(new IProject[projectList.size()]);
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/SelectionUtil.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/SelectionUtil.java
new file mode 100644
index 00000000..7955c654
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/SelectionUtil.java
@@ -0,0 +1,360 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+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.NullProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.IStorageEditorInput;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+
+import org.codehaus.plexus.util.IOUtil;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.util.Util;
+import org.eclipse.m2e.core.util.Util.FileStoreEditorInputStub;
+import org.eclipse.m2e.model.edit.pom.Dependency;
+
+
+/**
+ * Helper methods to deal with workspace resources passed as navigator selection to actions and wizards.
+ */
+public class SelectionUtil {
+
+ public static final int UNSUPPORTED = 0;
+
+ public static final int PROJECT_WITH_NATURE = 1;
+
+ public static final int PROJECT_WITHOUT_NATURE = 2;
+
+ public static final int POM_FILE = 4;
+
+ public static final int JAR_FILE = 8;
+
+ public static final int WORKING_SET = 16;
+
+ /** Checks which type the given selection belongs to. */
+ public static int getSelectionType(IStructuredSelection selection) {
+ int type = UNSUPPORTED;
+ if(selection != null) {
+ for(Iterator<?> it = selection.iterator(); it.hasNext();) {
+ int elementType = getElementType(it.next());
+ if(elementType == UNSUPPORTED) {
+ return UNSUPPORTED;
+ }
+ type |= elementType;
+ }
+ }
+ return type;
+ }
+
+ /** Checks which type the given element belongs to. */
+ public static int getElementType(Object element) {
+ IProject project = getType(element, IProject.class);
+ if(project != null) {
+ try {
+ if(project.hasNature(IMavenConstants.NATURE_ID)) {
+ return PROJECT_WITH_NATURE;
+ }
+ return PROJECT_WITHOUT_NATURE;
+ } catch(CoreException e) {
+ // ignored
+ }
+ }
+
+ IFile file = getType(element, IFile.class);
+ if(file != null) {
+ if(IMavenConstants.POM_FILE_NAME.equals(file.getFullPath().lastSegment())) {
+ return POM_FILE;
+ }
+ }
+
+ ArtifactKey artifactKey = getType(element, ArtifactKey.class);
+ if(artifactKey != null) {
+ return JAR_FILE;
+ }
+
+ IWorkingSet workingSet = getType(element, IWorkingSet.class);
+ if(workingSet!=null) {
+ return WORKING_SET;
+ }
+
+ return UNSUPPORTED;
+ }
+
+ /**
+ * Checks if the object belongs to a given type and returns it or a suitable adapter.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T getType(Object element, Class<T> type) {
+ if(element==null) {
+ return null;
+ }
+ if(type.isInstance(element)) {
+ return (T) element;
+ }
+ if(element instanceof IAdaptable) {
+ T adapter = (T) ((IAdaptable) element).getAdapter(type);
+ if(adapter != null) {
+ return adapter;
+ }
+ }
+ return (T) Platform.getAdapterManager().getAdapter(element, type);
+ }
+
+ public static IPath getSelectedLocation(IStructuredSelection selection) {
+ Object element = selection == null ? null : selection.getFirstElement();
+
+ IPath path = getType(element, IPath.class);
+ if(path != null) {
+ return path;
+ }
+
+ IResource resource = getType(element, IResource.class);
+ if(resource != null) {
+ return resource.getLocation();
+ }
+
+// IPackageFragmentRoot fragment = getType(element, IResource.class);
+// if(fragment != null) {
+// IJavaProject javaProject = fragment.getJavaProject();
+// if(javaProject != null) {
+// IResource resource = getType(javaProject, IResource.class);
+// if(resource != null) {
+// return resource.getProject().getProject().getLocation();
+// }
+// }
+// }
+
+ return null;
+ }
+
+ public static IWorkingSet getSelectedWorkingSet(IStructuredSelection selection) {
+ Object element = selection == null ? null : selection.getFirstElement();
+ {
+ IWorkingSet workingSet = getType(element, IWorkingSet.class);
+ if(workingSet != null) {
+ return workingSet;
+ }
+ }
+ {
+ IResource resource = getType(element, IResource.class);
+ if(resource != null) {
+ return getWorkingSet(resource.getProject());
+ }
+ }
+
+// IResource resource = getType(element, IResource.class);
+// if(resource != null) {
+// return getWorkingSet(resource);
+// }
+
+// IPackageFragmentRoot fragment = getType(element, IPackageFragmentRoot.class);
+// if(fragment != null) {
+// IJavaProject javaProject = fragment.getJavaProject();
+// if(javaProject != null) {
+// IResource resource = getType(javaProject, IResource.class);
+// if(resource != null) {
+// return getWorkingSet(resource.getProject());
+// }
+// }
+// }
+
+ return null;
+ }
+
+ public static IWorkingSet getWorkingSet(Object element) {
+ IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
+ for(IWorkingSet workingSet : workingSetManager.getWorkingSets()) {
+ for(IAdaptable adaptable : workingSet.getElements()) {
+ if(adaptable.getAdapter(IResource.class) == element) {
+ return workingSet;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static IWorkingSet[] getAssignedWorkingSets(Object element) {
+ List<IWorkingSet> list = new ArrayList<IWorkingSet>();
+ IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
+ for(IWorkingSet workingSet : workingSetManager.getWorkingSets()) {
+ for(IAdaptable adaptable : workingSet.getElements()) {
+ if(adaptable.getAdapter(IResource.class) == element) {
+ list.add(workingSet);
+ }
+ }
+ }
+ return list.toArray(new IWorkingSet[list.size()]);
+ }
+
+ public static ArtifactKey getArtifactKey(Object element) throws CoreException {
+ if(element instanceof Artifact) {
+ return new ArtifactKey(((Artifact) element));
+
+ } else if(element instanceof org.sonatype.aether.graph.DependencyNode) {
+ org.sonatype.aether.artifact.Artifact artifact = ((org.sonatype.aether.graph.DependencyNode) element)
+ .getDependency().getArtifact();
+ return new ArtifactKey(artifact);
+
+ } else if(element instanceof Dependency) {
+ Dependency dependency = (Dependency) element;
+ String groupId = dependency.getGroupId();
+ String artifactId = dependency.getArtifactId();
+ String version = dependency.getVersion();
+
+ if(version == null) {
+ //mkleint: this looks scary
+ IEditorPart editor = getActiveEditor();
+ if(editor!=null) {
+ MavenProject mavenProject = getMavenProject(editor.getEditorInput(), null);
+ if(mavenProject!=null) {
+ Artifact a = mavenProject.getArtifactMap().get(groupId + ":" + artifactId); //$NON-NLS-1$
+ version = a.getBaseVersion();
+ }
+ }
+ }
+ return new ArtifactKey(dependency.getGroupId(), dependency.getArtifactId(), version, null);
+ }
+
+ return SelectionUtil.getType(element, ArtifactKey.class);
+ }
+
+ public static MavenProject getMavenProject(IEditorInput editorInput, IProgressMonitor monitor) throws CoreException {
+ if(editorInput instanceof IFileEditorInput) {
+ IFile pomFile = ((IFileEditorInput) editorInput).getFile();
+ MavenProjectManager projectManager = MavenPlugin.getDefault().getMavenProjectManager();
+ IMavenProjectFacade facade = projectManager.create(pomFile, true, monitor);
+ if(facade!=null) {
+ return facade.getMavenProject(monitor);
+ }
+
+ } else if(editorInput instanceof IStorageEditorInput) {
+ IStorageEditorInput storageInput = (IStorageEditorInput) editorInput;
+ IStorage storage = storageInput.getStorage();
+ IPath path = storage.getFullPath();
+ if(path == null || !new File(path.toOSString()).exists()) {
+ File tempPomFile = null;
+ InputStream is = null;
+ OutputStream os = null;
+ try {
+ tempPomFile = File.createTempFile("maven-pom", ".pom"); //$NON-NLS-1$ //$NON-NLS-2$
+ os = new FileOutputStream(tempPomFile);
+ is = storage.getContents();
+ IOUtil.copy(is, os);
+ return readMavenProject(tempPomFile, monitor);
+ } catch(IOException ex) {
+ MavenLogger.log("Can't close stream", ex);
+ } finally {
+ IOUtil.close(is);
+ IOUtil.close(os);
+ if(tempPomFile != null) {
+ tempPomFile.delete();
+ }
+ }
+ } else {
+ return readMavenProject(path.toFile(), monitor);
+ }
+
+ } else if(editorInput.getClass().getName().endsWith("FileStoreEditorInput")) { //$NON-NLS-1$
+ return readMavenProject(new File(Util.proxy(editorInput, FileStoreEditorInputStub.class).getURI().getPath()), monitor);
+ }
+
+ return null;
+ }
+
+ private static MavenProject readMavenProject(File pomFile, IProgressMonitor monitor) throws CoreException {
+ if(monitor==null) {
+ monitor = new NullProgressMonitor();
+ }
+
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+
+ MavenExecutionRequest request = maven.createExecutionRequest(monitor);
+ request.setOffline(false);
+ request.setUpdateSnapshots(false);
+ request.setRecursive(false);
+ request.setPom(pomFile);
+
+ MavenExecutionResult result = maven.execute(request, monitor);
+
+ MavenProject project = result.getProject();
+ if(project!=null) {
+ return project;
+ }
+
+ if(result.hasExceptions()) {
+ List<IStatus> statuses = new ArrayList<IStatus>();
+ List<Throwable> exceptions = result.getExceptions();
+ for(Throwable e : exceptions) {
+ statuses.add(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, e.getMessage(), e));
+ }
+
+ throw new CoreException(new MultiStatus(IMavenConstants.PLUGIN_ID, IStatus.ERROR, //
+ statuses.toArray(new IStatus[statuses.size()]), Messages.SelectionUtil_error_cannot_read, null));
+ }
+
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, //
+ Messages.SelectionUtil_error_cannot_read, null));
+ }
+
+ private static IEditorPart getActiveEditor() {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if(window != null) {
+ IWorkbenchPage page = window.getActivePage();
+ if(page != null) {
+ return page.getActiveEditor();
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/UpdateConfigurationAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/UpdateConfigurationAction.java
new file mode 100644
index 00000000..e8adb704
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/actions/UpdateConfigurationAction.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.actions;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.WorkspaceJob;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.progress.IProgressConstants;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.util.M2EUtils;
+
+
+public class UpdateConfigurationAction implements IObjectActionDelegate {
+
+ public static final String ID = "org.eclipse.m2e.updateConfigurationAction"; //$NON-NLS-1$
+
+ private IStructuredSelection selection;
+
+ private Shell shell;
+
+ public UpdateConfigurationAction(Shell shell) {
+ this.shell = shell;
+ }
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ if(selection instanceof IStructuredSelection) {
+ this.selection = (IStructuredSelection) selection;
+ } else {
+ this.selection = null;
+ }
+ }
+
+ public void run(IAction action) {
+ final Set<IProject> projects = getProjects();
+ final MavenPlugin plugin = MavenPlugin.getDefault();
+ WorkspaceJob job = new WorkspaceJob(Messages.UpdateSourcesAction_job_update_conf) {
+ public IStatus runInWorkspace(IProgressMonitor monitor) {
+ setProperty(IProgressConstants.ACTION_PROPERTY, new OpenMavenConsoleAction());
+ monitor.beginTask(getName(), projects.size());
+
+ MavenConsole console = plugin.getConsole();
+
+ long l1 = System.currentTimeMillis();
+ console.logMessage("Update started");
+
+ MultiStatus status = null;
+ //project names to the errors encountered when updating them
+ Map<String, Throwable> updateErrors = new HashMap<String, Throwable>();
+
+ for(IProject project : projects) {
+ if(monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+
+ monitor.subTask(project.getName());
+ IMavenProjectFacade projectFacade = plugin.getMavenProjectManager().create(project, monitor);
+ if(projectFacade != null) {
+ try {
+ plugin.getProjectConfigurationManager().updateProjectConfiguration(project, //
+ projectFacade.getResolverConfiguration(), //
+ new SubProgressMonitor(monitor, 1));
+ } catch(CoreException ex) {
+ if(status == null) {
+ status = new MultiStatus(IMavenConstants.PLUGIN_ID, IStatus.ERROR, //
+ Messages.UpdateSourcesAction_error_cannot_update, null);
+ }
+ status.add(ex.getStatus());
+ updateErrors.put(project.getName(), ex);
+ } catch(IllegalArgumentException e) {
+ status = new MultiStatus(IMavenConstants.PLUGIN_ID, IStatus.ERROR, //
+ Messages.UpdateSourcesAction_error_cannot_update, null);
+ updateErrors.put(project.getName(), e);
+ }
+ }
+ }
+ if(updateErrors.size() > 0) {
+ M2EUtils.showErrorsForProjectsDialog(shell, Messages.UpdateSourcesAction_error_title,
+ Messages.UpdateSourcesAction_error_message, updateErrors);
+ }
+ long l2 = System.currentTimeMillis();
+ console.logMessage(NLS.bind("Update completed: {0} sec", ((l2 - l1) / 1000)));
+
+ return status != null ? status : Status.OK_STATUS;
+ }
+ };
+ // We need to grab workspace lock because IJavaProject.setRawClasspath() needs it.
+ job.setRule(plugin.getProjectConfigurationManager().getRule());
+ job.schedule();
+ }
+
+ private Set<IProject> getProjects() {
+ Set<IProject> projects = new LinkedHashSet<IProject>();
+ if(selection != null) {
+ for(Iterator<?> it = selection.iterator(); it.hasNext();) {
+ Object element = it.next();
+ if(element instanceof IProject) {
+ projects.add((IProject) element);
+ } else if(element instanceof IWorkingSet) {
+ IWorkingSet workingSet = (IWorkingSet) element;
+ for(IAdaptable adaptable : workingSet.getElements()) {
+ IProject project = (IProject) adaptable.getAdapter(IProject.class);
+ try {
+ if(project != null && project.isAccessible() && project.hasNature(IMavenConstants.NATURE_ID)) {
+ projects.add(project);
+ }
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ } else if(element instanceof IAdaptable) {
+ IProject project = (IProject) ((IAdaptable) element).getAdapter(IProject.class);
+ if(project != null) {
+ projects.add(project);
+ }
+ }
+ }
+ }
+ return projects;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeCatalogFactory.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeCatalogFactory.java
new file mode 100644
index 00000000..8b9331bd
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeCatalogFactory.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.archetype;
+
+import java.util.Properties;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+
+import org.apache.maven.archetype.Archetype;
+import org.apache.maven.archetype.catalog.ArchetypeCatalog;
+import org.apache.maven.archetype.source.ArchetypeDataSource;
+import org.apache.maven.archetype.source.ArchetypeDataSourceException;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * Abstract ArchetypeCatalog factory
+ */
+public abstract class ArchetypeCatalogFactory {
+ private final String id;
+
+ private final String description;
+
+ private final boolean editable;
+
+ public ArchetypeCatalogFactory(String id, String description, boolean editable) {
+ this.id = id;
+ this.description = description;
+ this.editable = editable;
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public String getDescription() {
+ return this.description;
+ }
+
+ public boolean isEditable() {
+ return editable;
+ }
+
+ public abstract ArchetypeCatalog getArchetypeCatalog() throws CoreException;
+
+ public String toString() {
+ return getId();
+ }
+
+ protected Archetype getArchetyper() {
+ return MavenPlugin.getDefault().getArchetype();
+ }
+
+ /**
+ * Factory for Nexus Indexer ArchetypeCatalog
+ */
+ public static class NexusIndexerCatalogFactory extends ArchetypeCatalogFactory {
+ public static final String ID = "nexusIndexer"; //$NON-NLS-1$
+
+ public NexusIndexerCatalogFactory() {
+ super(ID, Messages.ArchetypeCatalogFactory_indexer_catalog, false);
+ }
+
+ public ArchetypeCatalog getArchetypeCatalog() throws CoreException {
+ try {
+ ArchetypeDataSource source = MavenPlugin.getDefault().getArchetypeDataSource("nexus"); //$NON-NLS-1$
+ return source.getArchetypeCatalog(new Properties());
+ } catch(ArchetypeDataSourceException ex) {
+ String msg = NLS.bind(Messages.ArchetypeCatalogFactory_error_missing_catalog, ex.getMessage());
+ MavenLogger.log(msg, ex);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, msg, ex));
+ }
+ }
+
+ }
+
+ /**
+ * Factory for internal ArchetypeCatalog
+ */
+ public static class InternalCatalogFactory extends ArchetypeCatalogFactory {
+ public static final String ID = "internal"; //$NON-NLS-1$
+
+ public InternalCatalogFactory() {
+ super(ID, Messages.ArchetypeCatalogFactory_internal, false);
+ }
+
+ public ArchetypeCatalog getArchetypeCatalog() {
+ return getArchetyper().getInternalCatalog();
+ }
+ }
+
+ /**
+ * Factory for default local ArchetypeCatalog
+ */
+ public static class DefaultLocalCatalogFactory extends ArchetypeCatalogFactory {
+ public static final String ID = "defaultLocal"; //$NON-NLS-1$
+
+ public DefaultLocalCatalogFactory() {
+ super(ID, Messages.ArchetypeCatalogFactory_default_local, false);
+ }
+
+ public ArchetypeCatalog getArchetypeCatalog() {
+ return getArchetyper().getDefaultLocalCatalog();
+ }
+ }
+
+ /**
+ * Factory for local ArchetypeCatalog
+ */
+ public static class LocalCatalogFactory extends ArchetypeCatalogFactory {
+
+ public LocalCatalogFactory(String path, String description, boolean editable) {
+ super(path, description == null || description.trim().length() == 0 ? NLS.bind(Messages.ArchetypeCatalogFactory_local, path) : description, editable);
+ }
+
+ public ArchetypeCatalog getArchetypeCatalog() {
+ return getArchetyper().getLocalCatalog(getId());
+ }
+ }
+
+ /**
+ * Factory for remote ArchetypeCatalog
+ */
+ public static class RemoteCatalogFactory extends ArchetypeCatalogFactory {
+
+ private String repositoryUrl = null;
+
+ public RemoteCatalogFactory(String url, String description, boolean editable) {
+ super(url, description == null || description.trim().length() == 0 ? NLS.bind(Messages.ArchetypeCatalogFactory_remote, url) : description, editable);
+ repositoryUrl = parseCatalogUrl(url);
+ }
+
+ /**
+ * @param url
+ * @return
+
+ */
+ private String parseCatalogUrl(String url) {
+ if (url == null) {
+ return null;
+ }
+ int length = url.length();
+ if (length > 1 && url.endsWith("/")) //$NON-NLS-1$
+ {
+ return url.substring(0, url.length()-1);
+ }
+ int idx = url.lastIndexOf("/"); //$NON-NLS-1$
+ idx = (idx>0)?idx:0;
+ if (url.lastIndexOf(".") >= idx) { //$NON-NLS-1$
+ //Assume last fragment of the url is a file, let's keep its parent folder
+ return url.substring(0, idx);
+ }
+ return url;
+ }
+
+ public ArchetypeCatalog getArchetypeCatalog() {
+ return getArchetyper().getRemoteCatalog(getId());
+ }
+
+
+ /**
+ * @return the url of the remote repository hosting the catalog
+ */
+ public String getRepositoryUrl() {
+ return repositoryUrl;
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeCatalogsWriter.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeCatalogsWriter.java
new file mode 100644
index 00000000..aecc0a6d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeCatalogsWriter.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.archetype;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLFilterImpl;
+
+import org.eclipse.osgi.util.NLS;
+
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory.LocalCatalogFactory;
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory.RemoteCatalogFactory;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * Archetype catalogs writer
+ *
+ * @author Eugene Kuleshov
+ */
+public class ArchetypeCatalogsWriter {
+
+ private static final String ELEMENT_CATALOGS = "archetypeCatalogs"; //$NON-NLS-1$
+
+ private static final String ELEMENT_CATALOG = "catalog"; //$NON-NLS-1$
+
+ private static final String ATT_CATALOG_TYPE = "type"; //$NON-NLS-1$
+
+ private static final String ATT_CATALOG_LOCATION = "location"; //$NON-NLS-1$
+
+ public static final String ATT_CATALOG_DESCRIPTION = "description"; //$NON-NLS-1$
+
+ private static final String TYPE_LOCAL = "local"; //$NON-NLS-1$
+
+ private static final String TYPE_REMOTE = "remote"; //$NON-NLS-1$
+
+
+ public Collection<ArchetypeCatalogFactory> readArchetypeCatalogs(InputStream is) throws IOException {
+ Collection<ArchetypeCatalogFactory> catalogs = new ArrayList<ArchetypeCatalogFactory>();
+ try {
+ SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+ SAXParser parser = parserFactory.newSAXParser();
+ parser.parse(is, new ArchetypeCatalogsContentHandler(catalogs));
+ } catch(SAXException ex) {
+ String msg = Messages.ArchetypeCatalogsWriter_error_parse;
+ MavenLogger.log(msg, ex);
+ throw new IOException(NLS.bind(msg, ex.getMessage()));
+ } catch(ParserConfigurationException ex) {
+ String msg = Messages.ArchetypeCatalogsWriter_error_parse;
+ MavenLogger.log(msg, ex);
+ throw new IOException(NLS.bind(msg, ex.getMessage()));
+ }
+ return catalogs;
+ }
+
+ public void writeArchetypeCatalogs(final Collection<ArchetypeCatalogFactory> catalogs, OutputStream os) throws IOException {
+ try {
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.transform(new SAXSource(new XMLArchetypeCatalogsWriter(catalogs), new InputSource()), new StreamResult(os));
+
+ } catch(TransformerFactoryConfigurationError ex) {
+ throw new IOException(NLS.bind(Messages.ArchetypeCatalogsWriter_error_write, ex.getMessage()));
+
+ } catch(TransformerException ex) {
+ throw new IOException(NLS.bind(Messages.ArchetypeCatalogsWriter_error_write, ex.getMessage()));
+
+ }
+ }
+
+ static class XMLArchetypeCatalogsWriter extends XMLFilterImpl {
+
+ private final Collection<ArchetypeCatalogFactory> catalogs;
+
+ public XMLArchetypeCatalogsWriter(Collection<ArchetypeCatalogFactory> catalogs) {
+ this.catalogs = catalogs;
+ }
+
+ public void parse(InputSource input) throws SAXException {
+ ContentHandler handler = getContentHandler();
+ handler.startDocument();
+ handler.startElement(null, ELEMENT_CATALOGS, ELEMENT_CATALOGS, new AttributesImpl());
+
+ for(ArchetypeCatalogFactory factory : this.catalogs) {
+ if(factory.isEditable()) {
+ if(factory instanceof LocalCatalogFactory) {
+ AttributesImpl attrs = new AttributesImpl();
+ attrs.addAttribute(null, ATT_CATALOG_TYPE, ATT_CATALOG_TYPE, null, TYPE_LOCAL);
+ attrs.addAttribute(null, ATT_CATALOG_LOCATION, ATT_CATALOG_LOCATION, null, factory.getId());
+ attrs.addAttribute(null, ATT_CATALOG_DESCRIPTION, ATT_CATALOG_DESCRIPTION, null, factory.getDescription());
+ handler.startElement(null, ELEMENT_CATALOG, ELEMENT_CATALOG, attrs);
+ handler.endElement(null, ELEMENT_CATALOG, ELEMENT_CATALOG);
+ } else if(factory instanceof RemoteCatalogFactory) {
+ AttributesImpl attrs = new AttributesImpl();
+ attrs.addAttribute(null, ATT_CATALOG_TYPE, ATT_CATALOG_TYPE, null, TYPE_REMOTE);
+ attrs.addAttribute(null, ATT_CATALOG_LOCATION, ATT_CATALOG_LOCATION, null, factory.getId());
+ attrs.addAttribute(null, ATT_CATALOG_DESCRIPTION, ATT_CATALOG_DESCRIPTION, null, factory.getDescription());
+ handler.startElement(null, ELEMENT_CATALOG, ELEMENT_CATALOG, attrs);
+ handler.endElement(null, ELEMENT_CATALOG, ELEMENT_CATALOG);
+ }
+ }
+ }
+
+ handler.endElement(null, ELEMENT_CATALOGS, ELEMENT_CATALOGS);
+ handler.endDocument();
+ }
+ }
+
+ static class ArchetypeCatalogsContentHandler extends DefaultHandler {
+
+ private Collection<ArchetypeCatalogFactory> catalogs;
+
+ public ArchetypeCatalogsContentHandler(Collection<ArchetypeCatalogFactory> catalogs) {
+ this.catalogs = catalogs;
+ }
+
+ public void startElement(String uri, String localName, String qName, Attributes attributes) {
+ if(ELEMENT_CATALOG.equals(qName) && attributes != null) {
+ String type = attributes.getValue(ATT_CATALOG_TYPE);
+ if(TYPE_LOCAL.equals(type)) {
+ String path = attributes.getValue(ATT_CATALOG_LOCATION);
+ if(path!=null) {
+ String description = attributes.getValue(ATT_CATALOG_DESCRIPTION);
+ catalogs.add(new LocalCatalogFactory(path, description, true));
+ }
+ } else if(TYPE_REMOTE.equals(type)) {
+ String url = attributes.getValue(ATT_CATALOG_LOCATION);
+ if(url!=null) {
+ String description = attributes.getValue(ATT_CATALOG_DESCRIPTION);
+ catalogs.add(new RemoteCatalogFactory(url, description, true));
+ }
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeManager.java
new file mode 100644
index 00000000..e447e2de
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/archetype/ArchetypeManager.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.archetype;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.codehaus.plexus.util.IOUtil;
+
+import org.apache.maven.archetype.catalog.Archetype;
+
+
+
+
+/**
+ * Archetype Manager
+ *
+ * @author Eugene Kuleshov
+ */
+public class ArchetypeManager {
+
+ private final Map<String, ArchetypeCatalogFactory> catalogs = new LinkedHashMap<String, ArchetypeCatalogFactory>();
+
+ private final File configFile;
+
+ private final ArchetypeCatalogsWriter writer;
+
+ public ArchetypeManager(File configFile) {
+ this.configFile = configFile;
+ this.writer = new ArchetypeCatalogsWriter();
+ }
+
+ /**
+ * @return Collection of ArchetypeCatalogFactory
+ */
+ public Collection<ArchetypeCatalogFactory> getArchetypeCatalogs() {
+ return new ArrayList<ArchetypeCatalogFactory>(catalogs.values());
+ }
+
+ public void addArchetypeCatalogFactory(ArchetypeCatalogFactory factory) {
+ if(factory != null) {
+ catalogs.put(factory.getId(), factory);
+ }
+ }
+
+ public void removeArchetypeCatalogFactory(String catalogId) {
+ catalogs.remove(catalogId);
+ }
+
+ public ArchetypeCatalogFactory getArchetypeCatalogFactory(String catalogId) {
+ return catalogs.get(catalogId);
+ }
+
+ public void readCatalogs() throws IOException {
+ if(configFile.exists()) {
+ InputStream is = null;
+ try {
+ is = new FileInputStream(configFile);
+ Collection<ArchetypeCatalogFactory> catalogs = writer.readArchetypeCatalogs(is);
+ for(Iterator<ArchetypeCatalogFactory> it = catalogs.iterator(); it.hasNext();) {
+ addArchetypeCatalogFactory(it.next());
+ }
+ } finally {
+ IOUtil.close(is);
+ }
+ }
+ }
+
+ public void saveCatalogs() throws IOException {
+ OutputStream os = null;
+ try {
+ os = new FileOutputStream(configFile);
+ writer.writeArchetypeCatalogs(getArchetypeCatalogs(), os);
+ } finally {
+ IOUtil.close(os);
+ }
+ }
+
+ /**
+ * @return the archetypeCatalogFactory containing the archetype parameter, null if none was found.
+ */
+ public <T extends ArchetypeCatalogFactory> T findParentCatalogFactory(Archetype a, Class<T> type) throws CoreException {
+ if (a!=null){
+ for (ArchetypeCatalogFactory factory : getArchetypeCatalogs()) {
+ if ((type.isAssignableFrom(factory.getClass()))
+ //temporary hack to get around https://issues.sonatype.org/browse/MNGECLIPSE-1792
+ //cf. MavenProjectWizardArchetypePage.getAllArchetypes
+ && !(factory.getDescription() != null && factory.getDescription().startsWith("Test")) //$NON-NLS-1$
+ && factory.getArchetypeCatalog().getArchetypes().contains(a)) {
+ return (T)factory;
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/AbstractEclipseBuildContext.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/AbstractEclipseBuildContext.java
new file mode 100644
index 00000000..df3a519d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/AbstractEclipseBuildContext.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.builder;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+import org.sonatype.plexus.build.incremental.BuildContext;
+
+
+/**
+ * AbstractEclipseBuildContext
+ *
+ * @author igor
+ */
+public abstract class AbstractEclipseBuildContext implements BuildContext {
+
+ public static class Message {
+ public final File file;
+
+ public final int line;
+
+ public final int column;
+
+ public final String message;
+
+ public final Throwable cause;
+
+ Message(File file, int line, int column, String message, Throwable cause) {
+ this.file = file;
+ this.line = line;
+ this.column = column;
+ this.message = message;
+ this.cause = cause;
+ }
+ }
+
+ private final Set<File> refresh = new HashSet<File>();
+
+ protected final Map<String, Object> context;
+
+ private final ArrayList<Message> errorMessages = new ArrayList<Message>();
+
+ private final ArrayList<Message> warningMessages = new ArrayList<Message>();
+
+ protected AbstractEclipseBuildContext(Map<String, Object> context) {
+ this.context = context;
+ }
+
+ public void refresh(File file) {
+ refresh.add(file);
+ }
+
+ public Set<File> getFiles() {
+ return refresh;
+ }
+
+ public OutputStream newFileOutputStream(File file) throws IOException {
+ return new ChangedFileOutputStream(file, this);
+ }
+
+ /**
+ * Returns path relative to delta resource location.
+ */
+ protected IPath getRelativePath(File file) {
+ IPath basepath = getBaseResource().getLocation();
+ IPath path = Path.fromOSString(file.getAbsolutePath());
+
+ if(!basepath.isPrefixOf(path)) {
+ return null;
+ }
+
+ return path.removeFirstSegments(basepath.segmentCount());
+ }
+
+ protected IResource getResource(File file) {
+ IPath relpath = getRelativePath(file);
+ if (relpath == null) {
+ return null;
+ }
+ IResource baseResource = getBaseResource();
+ if (baseResource instanceof IContainer) {
+ return ((IContainer) baseResource).findMember(relpath);
+ }
+ return null;
+ }
+
+ protected abstract IResource getBaseResource();
+
+ public void setValue(String key, Object value) {
+ context.put(key, value);
+ }
+
+ public Object getValue(String key) {
+ return context.get(key);
+ }
+
+ public void addError(File file, int line, int column, String message, Throwable cause) {
+ errorMessages.add(new Message(file, line, column, message, cause));
+ }
+
+ public void addWarning(File file, int line, int column, String message, Throwable cause) {
+ warningMessages.add(new Message(file, line, column, message, cause));
+ }
+
+ public List<Message> getErrorMessages() {
+ return errorMessages;
+ }
+
+ public List<Message> getWarningMessages() {
+ return warningMessages;
+ }
+
+ public boolean isUptodate(File target, File source) {
+ IResource targetResource = getResource(target);
+ IResource sourceResource = getResource(source);
+ return targetResource != null && targetResource.isAccessible() && !hasDelta(target)
+ && sourceResource != null && sourceResource.isAccessible() && !hasDelta(source)
+ && targetResource.getLocalTimeStamp() >= sourceResource.getLocalTimeStamp();
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/ChangedFileOutputStream.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/ChangedFileOutputStream.java
new file mode 100644
index 00000000..51aa0093
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/ChangedFileOutputStream.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.builder;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.sonatype.plexus.build.incremental.BuildContext;
+
+/**
+ * Writes to the file only if content of the file is different.
+ *
+ * TODO. Current implementation defers actual writing to the output file until
+ * invocation of {@link #close()} method. This results in missed/ignored IOExceptions
+ * in some cases. First, {@link #flush()} method does not actually flush buffer to the disk.
+ * Second, any problems writing to the file will be reported as IOException
+ * thrown by {@link #close()}, which are generally ignored.
+ */
+public class ChangedFileOutputStream extends OutputStream {
+
+ private final File file;
+ private final BuildContext buildContext;
+ private final OutputStream os;
+
+ private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ public ChangedFileOutputStream(File file) throws FileNotFoundException {
+ this(file, null);
+ }
+
+ public ChangedFileOutputStream(File file, BuildContext buildContext) throws FileNotFoundException {
+ this.file = file;
+ this.buildContext = buildContext;
+ this.os = new BufferedOutputStream(new FileOutputStream(file));
+ }
+
+ public void write(int b) {
+ buffer.write(b);
+ }
+
+ public void write(byte[] b, int off, int len) {
+ buffer.write(b, off, len);
+ }
+
+ public void close() throws IOException {
+ try {
+ writeIfNewOrChanged();
+ } finally {
+ os.close();
+ }
+ }
+
+ protected void writeIfNewOrChanged() throws IOException {
+ byte[] bytes = buffer.toByteArray();
+
+ boolean needToWrite = false;
+
+ // XXX harden
+ if (file.exists()) {
+ BufferedInputStream is = new BufferedInputStream(new FileInputStream(file));
+ try {
+ for (int i = 0; i < bytes.length; i++) {
+ if (bytes[i] != is.read()) {
+ needToWrite = true;
+ break;
+ }
+ }
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+
+ }
+ }
+ } else {
+ // file does not exist
+ needToWrite = true;
+ }
+
+ if (needToWrite) {
+ if (buildContext != null) {
+ buildContext.refresh(file);
+ }
+
+ os.write(bytes);
+ }
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/EclipseBuildContext.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/EclipseBuildContext.java
new file mode 100644
index 00000000..c5161f7d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/EclipseBuildContext.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.builder;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+
+import org.codehaus.plexus.util.Scanner;
+
+import org.sonatype.plexus.build.incremental.EmptyScanner;
+
+import org.eclipse.m2e.core.internal.builder.ResourceScanner;
+
+/**
+ * EclipseBuildContext
+ *
+ * @author igor
+ */
+public class EclipseBuildContext extends AbstractEclipseBuildContext {
+
+ protected final IProject project;
+
+ public EclipseBuildContext(IProject project, Map<String, Object> context) {
+ super(context);
+ this.project = project;
+ }
+
+ public boolean hasDelta(String relpath) {
+ return true;
+ }
+
+ @SuppressWarnings("rawtypes")
+ public boolean hasDelta(List relpath) {
+ return true;
+ }
+
+ public boolean hasDelta(File file) {
+ return true;
+ }
+
+ public Scanner newDeleteScanner(File basedir) {
+ return new EmptyScanner(basedir);
+ }
+
+ public Scanner newScanner(File basedir) {
+ IPath relpath = getRelativePath(basedir);
+ return new ResourceScanner(project.findMember(relpath));
+ }
+
+ public Scanner newScanner(File basedir, boolean ignoreDelta) {
+ return newScanner(basedir);
+ }
+
+ protected IProject getBaseResource() {
+ return project;
+ }
+
+ public boolean isIncremental() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/EclipseIncrementalBuildContext.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/EclipseIncrementalBuildContext.java
new file mode 100644
index 00000000..e5f039fb
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/EclipseIncrementalBuildContext.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.builder;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+import org.codehaus.plexus.util.DirectoryScanner;
+import org.codehaus.plexus.util.Scanner;
+
+import org.sonatype.plexus.build.incremental.EmptyScanner;
+
+public class EclipseIncrementalBuildContext extends AbstractEclipseBuildContext {
+
+ private final IResourceDelta delta;
+
+ public EclipseIncrementalBuildContext(IResourceDelta delta, Map<String, Object> context) {
+ super(context);
+ this.delta = delta;
+ }
+
+ public boolean hasDelta(String relPath) {
+ IPath path = new Path(relPath);
+ return hasDelta(path);
+ }
+
+ protected boolean hasDelta(IPath path) {
+ return delta == null || path == null || delta.findMember(path) != null;
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public boolean hasDelta(List relPaths) {
+ for (String relPath : (List<String>) relPaths) {
+ if (hasDelta(relPath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean hasDelta(File file) {
+ return hasDelta(getRelativePath(file));
+ }
+
+ public Scanner newDeleteScanner(File basedir) {
+ IResourceDelta reldelta = getDelta(basedir);
+
+ if (reldelta == null || !isRemove(reldelta)) {
+ return new EmptyScanner(basedir);
+ }
+
+ return new ResourceDeltaScanner(reldelta, true);
+ }
+
+ public Scanner newScanner(File basedir) {
+ return newScanner(basedir, false);
+ }
+
+ public Scanner newScanner(File basedir, boolean ignoreDelta) {
+ if (!ignoreDelta) {
+ IResourceDelta reldelta = getDelta(basedir);
+
+ if (reldelta == null || !isContentChange(reldelta)) {
+ return new EmptyScanner(basedir);
+ }
+
+ return new ResourceDeltaScanner(reldelta, false);
+ }
+
+ DirectoryScanner ds = new DirectoryScanner();
+ ds.setBasedir(basedir);
+ return ds;
+ }
+
+ private IResourceDelta getDelta(File file) {
+ IPath relpath = getRelativePath(file);
+ if (relpath == null) {
+ return null;
+ }
+ return delta.findMember(relpath);
+ }
+
+ static boolean isContentChange(IResourceDelta delta) {
+ int kind = delta.getKind();
+ if (IResourceDelta.ADDED == kind) {
+ return true;
+ }
+
+ if (IResourceDelta.CHANGED == kind) {
+ if (delta.getResource() instanceof IContainer) {
+ return true;
+ }
+
+ int flags = delta.getFlags();
+
+ return (flags & IResourceDelta.CONTENT) != 0;
+ }
+
+ return false;
+ }
+
+ static boolean isRemove(IResourceDelta delta) {
+ int kind = delta.getKind();
+
+ if (IResourceDelta.REMOVED == kind) {
+ return true;
+ }
+
+ if (IResourceDelta.CHANGED == kind && delta.getResource() instanceof IContainer) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ @Override
+ protected IResource getBaseResource() {
+ return delta.getResource();
+ }
+
+ public boolean isIncremental() {
+ return true;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/ResourceDeltaScanner.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/ResourceDeltaScanner.java
new file mode 100644
index 00000000..092d419d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/builder/ResourceDeltaScanner.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.builder;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.runtime.CoreException;
+
+import org.codehaus.plexus.util.AbstractScanner;
+
+public class ResourceDeltaScanner extends AbstractScanner {
+
+ protected final IResourceDelta delta;
+
+ protected final List<String> includedDirectories = new ArrayList<String>();
+
+ protected final List<String> includedFiles = new ArrayList<String>();
+
+ protected final boolean deleted;
+
+ public ResourceDeltaScanner(IResourceDelta delta, boolean deleted) {
+ this.delta = delta;
+ this.deleted = deleted;
+ }
+
+ public String[] getIncludedDirectories() {
+ return includedDirectories.toArray(new String[includedDirectories.size()]);
+ }
+
+ public String[] getIncludedFiles() {
+ return includedFiles.toArray(new String[includedFiles.size()]);
+ }
+
+ public void scan() {
+ try {
+ setupDefaultFilters();
+ scanDelta();
+ } catch(CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private void scanDelta() throws CoreException {
+ delta.accept(new IResourceDeltaVisitor() {
+
+ @SuppressWarnings("synthetic-access")
+ public boolean visit(IResourceDelta delta) {
+ String relpath = getRelativePath(delta);
+ if (isInteresting(delta) && isIncluded(relpath) && !isExcluded(relpath)) {
+ IResource resource = delta.getResource();
+ if (resource instanceof IContainer) {
+ includedDirectories.add(relpath);
+ } else {
+ includedFiles.add(relpath);
+ }
+ return true;
+ } else if (delta.getResource() instanceof IFolder) {
+ return couldHoldIncluded(relpath);
+ }
+
+ return false;
+ }
+
+ });
+ }
+
+ protected boolean isInteresting(IResourceDelta delta) {
+ return deleted? EclipseIncrementalBuildContext.isRemove(delta): EclipseIncrementalBuildContext.isContentChange(delta);
+ }
+
+ protected String getRelativePath(IResourceDelta delta) {
+ return delta.getFullPath().removeFirstSegments(this.delta.getFullPath().segmentCount()).toOSString();
+ }
+
+ public File getBasedir() {
+ return delta.getResource().getLocation().toFile();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/IMavenConsoleListener.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/IMavenConsoleListener.java
new file mode 100644
index 00000000..1d1a7b93
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/IMavenConsoleListener.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.core;
+
+import java.util.EventListener;
+
+/**
+ * A console listener is notified of output to the Maven console.
+ *
+ * @author Benjamin Bentmann
+ */
+public interface IMavenConsoleListener extends EventListener {
+
+ void loggingMessage(String msg);
+
+ void loggingError(String msg);
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/IMavenConstants.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/IMavenConstants.java
new file mode 100644
index 00000000..fb9562d1
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/IMavenConstants.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.core;
+
+import org.eclipse.core.runtime.QualifiedName;
+
+/**
+ * Maven Constants
+ *
+ * @author Eugene Kuleshov
+ */
+public interface IMavenConstants {
+
+ public static final String PLUGIN_ID = "org.eclipse.m2e.core"; //$NON-NLS-1$
+
+ public static final String NATURE_ID = PLUGIN_ID + ".maven2Nature"; //$NON-NLS-1$
+
+ public static final String BUILDER_ID = PLUGIN_ID + ".maven2Builder"; //$NON-NLS-1$
+
+ public static final String MARKER_ID = PLUGIN_ID + ".maven2Problem"; //$NON-NLS-1$
+
+ public static final String MARKER_POM_LOADING_ID = MARKER_ID + ".pomloading"; //$NON-NLS-1$
+
+ public static final String MARKER_CONFIGURATION_ID = MARKER_ID + ".configuration"; //$NON-NLS-1$
+
+ public static final String MARKER_DEPENDENCY_ID = MARKER_ID + ".dependency"; //$NON-NLS-1$
+
+ public static final String MARKER_BUILD_ID = MARKER_ID + ".build"; //$NON-NLS-1$
+
+ /**
+ * string that gets included in pom.xml file comments and makes the marker manager to ignore
+ * the managed version override marker
+ */
+ public static final String MARKER_IGNORE_MANAGED = "$NO-MVN-MAN-VER$";//$NON-NLS-1$
+
+ public static final String MAVEN_COMPONENT_CONTRIBUTORS_XPT = PLUGIN_ID + ".mavenComponentContributors"; //$NON-NLS-1$
+
+ public static final String POM_FILE_NAME = "pom.xml"; //$NON-NLS-1$
+
+ public static final String PREFERENCE_PAGE_ID = PLUGIN_ID + ".MavenProjectPreferencePage"; //$NON-NLS-1$
+
+ public static final String NO_WORKSPACE_PROJECTS = "noworkspace"; //$NON-NLS-1$
+
+ public static final String ACTIVE_PROFILES = "profiles"; //$NON-NLS-1$
+
+ public static final String FILTER_RESOURCES = "filterresources"; //$NON-NLS-1$
+
+ public static final String JAVADOC_CLASSIFIER = "javadoc"; //$NON-NLS-1$
+
+ public static final String SOURCES_CLASSIFIER = "sources"; //$NON-NLS-1$
+
+
+ /**
+ * Session property key used to indicate that full maven build was requested for a project.
+ * It is not intended to be used by clients directly.
+ */
+ public static final QualifiedName FULL_MAVEN_BUILD = new QualifiedName(PLUGIN_ID, "fullBuild"); //$NON-NLS-1$
+
+ /**
+ * The name of the folder containing metadata information for the workspace.
+ */
+ public static final String METADATA_FOLDER = ".metadata"; //$NON-NLS-1$
+
+ public static final String INDEX_UPDATE_PROP = "indexUpdate"; //$NON-NLS-1$
+
+ public static final String MARKER_ATTR_EDITOR_HINT = "editor_hint";
+
+ public static final String EDITOR_HINT_PARENT_GROUP_ID = "parent_groupid";
+
+ public static final String EDITOR_HINT_PARENT_VERSION = "parent_version";
+
+ public static final String EDITOR_HINT_MANAGED_DEPENDENCY_OVERRIDE = "managed_dependency_override";
+
+ public static final String EDITOR_HINT_MANAGED_PLUGIN_OVERRIDE = "managed_plugin_override";
+
+ public static final String EDITOR_HINT_MISSING_SCHEMA = "missing_schema";
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/MavenConsole.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/MavenConsole.java
new file mode 100644
index 00000000..a6196d0f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/MavenConsole.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.core;
+
+import org.eclipse.ui.console.IConsole;
+import org.eclipse.ui.console.IConsoleListener;
+
+/**
+ * Maven Console
+ *
+ * @author Eugene Kuleshov
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface MavenConsole extends IConsole {
+
+ void logMessage(String msg);
+
+ void logError(String msg);
+
+ IConsoleListener newLifecycle();
+
+ void shutdown();
+
+ void showConsole();
+
+ void closeConsole();
+
+ void addMavenConsoleListener(IMavenConsoleListener listener);
+
+ void removeMavenConsoleListener(IMavenConsoleListener listener);
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/MavenLogger.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/MavenLogger.java
new file mode 100644
index 00000000..2cef32db
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/MavenLogger.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+
+/**
+ * Maven Logger
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenLogger {
+
+ private static ILog LOG;
+
+ public static void setLog(ILog log) {
+ LOG = log;
+ }
+
+ public static void log(IStatus status) {
+ LOG.log(status);
+ }
+
+ public static void log(CoreException ex) {
+ IStatus s = ex.getStatus();
+ if(s.getException() == null) {
+ int n = s.getSeverity();
+ log(new Status(n == IStatus.CANCEL || n == IStatus.ERROR || n == IStatus.INFO //
+ || n == IStatus.WARNING || n == IStatus.OK ? n : IStatus.ERROR, //
+ s.getPlugin() == null ? IMavenConstants.PLUGIN_ID : s.getPlugin(), //
+ s.getCode(), //
+ s.getMessage() == null ? s.toString() : s.getMessage(), //
+ ex));
+ } else {
+ log(s);
+ }
+ }
+
+ public static void log(String msg, Throwable t) {
+ log(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, msg, t));
+ }
+
+ public static void log(String msg) {
+ log(new Status(IStatus.OK, IMavenConstants.PLUGIN_ID, msg));
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/Messages.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/Messages.java
new file mode 100644
index 00000000..854797f1
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/core/Messages.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.core;
+
+import java.util.MissingResourceException;
+
+import com.ibm.icu.text.MessageFormat;
+import com.ibm.icu.util.ULocale;
+import com.ibm.icu.util.UResourceBundle;
+
+//mkleint: this class looks like not following the default eclipse way of i18n and resides in public packages
+
+public class Messages {
+ private static final String BUNDLE_NAME = IMavenConstants.PLUGIN_ID + ".messages"; //$NON-NLS-1$
+
+ private static final UResourceBundle RESOURCE_BUNDLE = UResourceBundle.getBundleInstance(BUNDLE_NAME,
+ ULocale.getDefault(), Messages.class.getClassLoader());
+
+ private Messages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch(MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+
+ public static String getString( String key, Object[] args ) {
+ try {
+ return MessageFormat.format(
+ RESOURCE_BUNDLE.getString( key ), args );
+ } catch( MissingResourceException e ) {
+ return '!' + key + '!';
+ }
+ }
+
+ public static String getString( String key, Object arg ) {
+ return getString( key, new Object[]{ arg } );
+ }
+
+ public static String getString( String key, int arg ) {
+ return getString( key, new Object[]{ String.valueOf(arg) } );
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/AbstractMavenConfigurationChangeListener.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/AbstractMavenConfigurationChangeListener.java
new file mode 100644
index 00000000..88d2538c
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/AbstractMavenConfigurationChangeListener.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+/**
+ * AbstractMavenConfigurationChangeListener
+ *
+ * @author igor
+ */
+public abstract class AbstractMavenConfigurationChangeListener implements IMavenConfigurationChangeListener {
+
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactKey.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactKey.java
new file mode 100644
index 00000000..d0697c1f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactKey.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import java.io.Serializable;
+
+import org.eclipse.osgi.util.NLS;
+
+import org.apache.maven.artifact.Artifact;
+
+public class ArtifactKey implements Serializable {
+ private static final long serialVersionUID = -8984509272834024387L;
+
+ private final String groupId;
+ private final String artifactId;
+ private final String version;
+ private final String classifier;
+
+ /**
+ * Note that this constructor uses Artifact.getBaseVersion
+ */
+ public ArtifactKey(Artifact a) {
+ this(a.getGroupId(), a.getArtifactId(), a.getBaseVersion(), null);
+ }
+
+ public ArtifactKey(org.sonatype.aether.artifact.Artifact a) {
+ this(a.getGroupId(), a.getArtifactId(), a.getBaseVersion(), null);
+ }
+
+ public ArtifactKey(String groupId, String artifactId, String version, String classifier) {
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.version = version;
+ this.classifier = classifier;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof ArtifactKey) {
+ ArtifactKey other = (ArtifactKey) o;
+ return equals(groupId, other.groupId)
+ && equals(artifactId, other.artifactId)
+ && equals(version, other.version)
+ && equals(classifier, other.classifier);
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ int hash = 17;
+ hash = hash * 31 + (groupId != null? groupId.hashCode(): 0);
+ hash = hash * 31 + (artifactId != null? artifactId.hashCode(): 0);
+ hash = hash * 31 + (version != null? version.hashCode(): 0);
+ hash = hash * 31 + (classifier != null? classifier.hashCode(): 0);
+ return hash;
+ }
+
+ private static boolean equals(Object o1, Object o2) {
+ return o1 == null? o2 == null: o1.equals(o2);
+ }
+
+ // XXX this method does not belong here, it compares versions, while ArtifactKey baseVersions
+ public static boolean equals(Artifact a1, Artifact a2) {
+ if (a1 == null) {
+ return a2 == null;
+ }
+ if (a2 == null) {
+ return false;
+ }
+ return equals(a1.getGroupId(), a2.getGroupId())
+ && equals(a1.getArtifactId(), a2.getArtifactId())
+ && equals(a1.getVersion(), a2.getVersion())
+ && equals(a1.getClassifier(), a2.getClassifier());
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(groupId).append(':').append(artifactId).append(':').append(version);
+ if(classifier != null) {
+ sb.append(':').append(classifier);
+ }
+ return sb.toString();
+ }
+
+ public static ArtifactKey fromPortableString(String str) {
+ int p, c;
+
+ p = 0; c = nextColonIndex(str, p);
+ String groupId = substring(str, p, c);
+
+ p = c + 1; c = nextColonIndex(str, p);
+ String artifactId = substring(str, p, c);
+
+ p = c + 1; c = nextColonIndex(str, p);
+ String version = substring(str, p, c);
+
+ p = c + 1; c = nextColonIndex(str, p);
+ String classifier = substring(str, p, c);
+
+ return new ArtifactKey(groupId, artifactId, version, classifier);
+ }
+
+ private static String substring(String str, int start, int end) {
+ String substring = str.substring(start, end);
+ return "".equals(substring)? null: substring; //$NON-NLS-1$
+ }
+
+ private static int nextColonIndex(String str, int pos) {
+ int idx = str.indexOf(':', pos);
+ if (idx < 0) throw new IllegalArgumentException(NLS.bind("Invalid portable string: {0}", str));
+ return idx;
+ }
+
+ public String toPortableString() {
+ StringBuilder sb = new StringBuilder();
+ if (groupId != null) sb.append(groupId); sb.append(':');
+ if (artifactId != null) sb.append(artifactId); sb.append(':');
+ if (version != null) sb.append(version); sb.append(':');
+ if (classifier != null) sb.append(classifier); sb.append(':');
+ return sb.toString();
+ }
+
+ public String getGroupId() {
+ return groupId;
+ }
+
+ public String getArtifactId() {
+ return artifactId;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public String getClassifier() {
+ return classifier;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactRef.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactRef.java
new file mode 100644
index 00000000..5d5ecb88
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactRef.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import java.io.Serializable;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+
+/**
+ * @author Igor Fedorenko
+ */
+public class ArtifactRef implements Serializable {
+ private static final long serialVersionUID = -7560496230862532267L;
+
+ private final ArtifactKey artifactKey;
+ private final String scope;
+
+ public ArtifactRef(Artifact artifact) {
+ this.artifactKey = new ArtifactKey(artifact);
+ this.scope = artifact.getScope();
+ }
+
+ public ArtifactKey getArtifactKey() {
+ return artifactKey;
+ }
+
+ public String getGroupId() {
+ return artifactKey.getGroupId();
+ }
+
+ public String getArtifactId() {
+ return artifactKey.getArtifactId();
+ }
+
+ public String getVersion() {
+ return artifactKey.getVersion();
+ }
+
+ public String getClassifier() {
+ return artifactKey.getClassifier();
+ }
+
+ public String getScope() {
+ return scope;
+ }
+
+ public static Set<ArtifactKey> toArtifactKey(Set<ArtifactRef> refs) {
+ LinkedHashSet<ArtifactKey> keys = new LinkedHashSet<ArtifactKey>(refs.size());
+ for (ArtifactRef ref : refs) {
+ keys.add(ref.getArtifactKey());
+ }
+ return keys;
+ }
+
+ public static Set<ArtifactRef> fromArtifact(Set<Artifact> artifacts) {
+ LinkedHashSet<ArtifactRef> refs = new LinkedHashSet<ArtifactRef>(artifacts.size());
+ for (Artifact artifact : artifacts) {
+ refs.add(new ArtifactRef(artifact));
+ }
+ return refs;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactRepositoryRef.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactRepositoryRef.java
new file mode 100644
index 00000000..d5a458ac
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ArtifactRepositoryRef.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import java.io.Serializable;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+
+
+public class ArtifactRepositoryRef implements Serializable {
+
+ private static final long serialVersionUID = 8859289246547259912L;
+
+ private final String id;
+
+ private final String url;
+
+ private final String username;
+
+ public ArtifactRepositoryRef(ArtifactRepository repository) {
+ this.id = repository.getId();
+ this.url = repository.getUrl();
+ this.username = repository.getAuthentication() != null? repository.getAuthentication().getUsername(): null;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public int hashCode() {
+ int hash = 17;
+ hash = hash * 31 + (id != null ? id.hashCode() : 0);
+ hash = hash * 31 + (url != null ? url.hashCode() : 0);
+ hash = hash * 31 + (username != null ? username.hashCode() : 0);
+ return hash;
+ }
+
+ public boolean equals(Object o) {
+ if(o == this) {
+ return true;
+ }
+ if(!(o instanceof ArtifactRepositoryRef)) {
+ return false;
+ }
+ ArtifactRepositoryRef other = (ArtifactRepositoryRef) o;
+ return eq(id, other.id) && eq(url, other.url) && eq(username, other.username);
+ }
+
+ private static <T> boolean eq(T a, T b) {
+ return a != null? a.equals(b): b == null;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ILocalRepositoryListener.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ILocalRepositoryListener.java
new file mode 100644
index 00000000..5a7d7211
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ILocalRepositoryListener.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import java.io.File;
+
+/**
+ * ILocalRepositoryListener
+ *
+ * @author igor
+ *
+ * @provisional This interface is provisional and can be changed or removed without notice
+ */
+public interface ILocalRepositoryListener {
+
+ /**
+ * New artifact has been downloaded or installed to maven local repository
+ */
+ public void artifactInstalled(File repositoryBasedir, ArtifactKey artifact, File artifactFile);
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java
new file mode 100644
index 00000000..651cf9a8
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.model.ConfigurationContainer;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.settings.Mirror;
+import org.apache.maven.settings.Server;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.building.SettingsProblem;
+import org.apache.maven.wagon.events.TransferListener;
+import org.apache.maven.wagon.proxy.ProxyInfo;
+
+/**
+ * Entry point for all Maven functionality in m2e. Note that this component does not directly support workspace artifact
+ * resolution.
+ *
+ * @author igor
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IMaven {
+
+ /**
+ * Creates new Maven execution request. This method is not long running, but created execution request is configured
+ * to report progress to provided progress monitor. Monitor can be null.
+ */
+ public MavenExecutionRequest createExecutionRequest(IProgressMonitor monitor) throws CoreException;
+
+ // POM Model read/write operations
+
+ public Model readModel(InputStream in) throws CoreException;
+
+ public Model readModel(File pomFile) throws CoreException;
+
+ public void writeModel(Model model, OutputStream out) throws CoreException;
+
+ // artifact resolution
+
+ /**
+ * Resolves specified artifact from specified remote repositories.
+ * @return Artifact resolved artifact
+ * @throws CoreException if the artifact cannot be resolved.
+ */
+ public Artifact resolve(String groupId, String artifactId, String version, String type, String classifier,
+ List<ArtifactRepository> artifactRepositories, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Returns path of the specified artifact relative to repository baseDir. Can use used to access local repository
+ * files bypassing maven resolution logic.
+ */
+ public String getArtifactPath(ArtifactRepository repository, String groupId, String artifactId, String version,
+ String type, String classifier) throws CoreException;
+
+ /**
+ * Returns true if the artifact does NOT exist in the local repository and
+ * known to be UNavailable from all specified repositories.
+ */
+ public boolean isUnavailable(String groupId, String artifactId, String version, String type, String classifier,
+ List<ArtifactRepository> repositories) throws CoreException;
+
+ // read MavenProject
+
+ public MavenProject readProject(File pomFile, IProgressMonitor monitor) throws CoreException;
+
+ public MavenExecutionResult readProject(MavenExecutionRequest request, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Makes MavenProject instances returned by #readProject methods suitable for caching and reuse with other
+ * MavenSession instances.<br/>
+ * Do note that MavenProject.getParentProject() cannot be used for detached MavenProject instances,
+ * #resolveParentProject to read parent project instance.
+ */
+ public void detachFromSession(MavenProject project) throws CoreException;
+
+ public MavenProject resolveParentProject(MavenExecutionRequest request, MavenProject project, IProgressMonitor monitor)
+ throws CoreException;
+
+ // execution
+
+ public MavenExecutionResult execute(MavenExecutionRequest request, IProgressMonitor monitor);
+
+ public MavenSession createSession(MavenExecutionRequest request, MavenProject project);
+
+ public void execute(MavenSession session, MojoExecution execution, IProgressMonitor monitor);
+
+ public MavenExecutionPlan calculateExecutionPlan(MavenExecutionRequest request, MavenProject project,
+ IProgressMonitor monitor) throws CoreException;
+
+ public <T> T getMojoParameterValue(MavenSession session, MojoExecution mojoExecution, String parameter,
+ Class<T> asType) throws CoreException;
+
+ public <T> T getMojoParameterValue(String parameter, Class<T> type, MavenSession session, Plugin plugin,
+ ConfigurationContainer configuration, String goal) throws CoreException;
+
+ // configuration
+
+ /**
+ * TODO should we expose Settings or provide access to servers and proxies instead?
+ */
+ public Settings getSettings() throws CoreException;
+
+ public String getLocalRepositoryPath();
+
+ public ArtifactRepository getLocalRepository() throws CoreException;
+
+ public void populateDefaults(MavenExecutionRequest request) throws CoreException;
+
+ public ArtifactRepository createArtifactRepository(String id, String url) throws CoreException;
+
+ /**
+ * Convenience method, fully equivalent to getArtifactRepositories(true)
+ */
+ public List<ArtifactRepository> getArtifactRepositories() throws CoreException;
+
+ /**
+ * Returns list of remote artifact repositories configured in settings.xml. Only profiles active by default are
+ * considered when calculating the list.
+ *
+ * If injectSettings=true, mirrors, authentication and proxy info will be injected.
+ *
+ * If injectSettings=false, raw repository definition will be used.
+ */
+ public List<ArtifactRepository> getArtifactRepositories(boolean injectSettings) throws CoreException;
+
+ public List<ArtifactRepository> getPluginArtifactRepositories() throws CoreException;
+
+ public List<ArtifactRepository> getPluginArtifactRepositories(boolean injectSettings) throws CoreException;
+
+ public Settings buildSettings(String globalSettings, String userSettings) throws CoreException;
+
+ public void writeSettings(Settings settings, OutputStream out) throws CoreException;
+
+ public List<SettingsProblem> validateSettings(String settings);
+
+ public List<Mirror> getMirrors() throws CoreException;
+
+ public Mirror getMirror(ArtifactRepository repo) throws CoreException;
+
+ public void addSettingsChangeListener(ISettingsChangeListener listener);
+
+ public void removeSettingsChangeListener(ISettingsChangeListener listener);
+
+ public void reloadSettings() throws CoreException;
+
+ public Server decryptPassword(Server server) throws CoreException;
+
+ /**
+ * Temporary solution/workaround for http://jira.codehaus.org/browse/MNG-4194. Extensions realm is created each time
+ * MavenProject instance is built, so we have to remove unused extensions realms to avoid OOME.
+ */
+ @Deprecated
+ public void xxxRemoveExtensionsRealm(MavenProject project);
+
+ /** @provisional */
+ public void addLocalRepositoryListener(ILocalRepositoryListener listener);
+
+ /** @provisional */
+ public void removeLocalRepositoryListener(ILocalRepositoryListener listener);
+
+ /**
+ * Creates wagon TransferListener that can be used with Archetype, NexusIndexer
+ * and other components that use wagon API directly. The listener will adopt
+ * wagon transfer events to corresponding calls to IProgressMonitor and all
+ * registered ILocalRepositoryListeners.
+ *
+ * @deprecated IMaven API should not expose maven.repository.ArtifactTransferListener
+ */
+ public TransferListener createTransferListener(IProgressMonitor monitor);
+
+ public ProxyInfo getProxyInfo(String protocol) throws CoreException;
+
+ /**
+ * Sort projects by build order
+ */
+ public List<MavenProject> getSortedProjects(List<MavenProject> projects) throws CoreException;
+
+ public String resolvePluginVersion(String groupId, String artifactId, MavenSession session) throws CoreException;
+
+ /**
+ * Returns new mojo instances configured according to provided mojoExecution. Caller must release returned mojo with
+ * {@link #releaseMojo(Object, MojoExecution)}. This method is intended to allow introspection of mojo configuration
+ * parameters, use {@link #execute(MavenSession, MojoExecution, IProgressMonitor)} to execute mojo.
+ */
+ public <T> T getConfiguredMojo(MavenSession session, MojoExecution mojoExecution, Class<T> clazz) throws CoreException;
+
+ /**
+ * Releases resources used by Mojo acquired with {@link #getConfiguredMojo(MavenSession, MojoExecution, Class)}
+ */
+ void releaseMojo(Object mojo, MojoExecution mojoExecution) throws CoreException;
+
+ /**
+ * Gets class realm of the specified project.
+ *
+ * @return The class realm of the specified project.
+ */
+ ClassLoader getProjectRealm(MavenProject project);
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java
new file mode 100644
index 00000000..1aed83b1
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+
+
+/**
+ * IMavenConfiguration
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IMavenConfiguration {
+
+ // listeners
+
+ public void addConfigurationChangeListener(IMavenConfigurationChangeListener listener);
+
+ //
+
+ public boolean isOffline();
+
+ public String getGlobalSettingsFile();
+
+ //settable for embedded maven
+ public void setGlobalSettingsFile(String absolutePath);
+
+ public String getUserSettingsFile();
+
+ public void setUserSettingsFile(String absolutePath);
+
+ // resolution
+
+ public boolean isDownloadSources();
+
+ public boolean isDownloadJavaDoc();
+
+ // problem reporting
+
+ public String getJiraUsername();
+
+ public String getJiraPassword();
+
+ // maven execution
+
+ public boolean isDebugOutput();
+
+ //
+
+ public boolean isUpdateProjectsOnStartup();
+
+ public boolean isUpdateIndexesOnStartup();
+
+ // new experimental preferences
+
+ public boolean isHideFoldersOfNestedProjects();
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfigurationChangeListener.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfigurationChangeListener.java
new file mode 100644
index 00000000..c23eeb22
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfigurationChangeListener.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * IMavenConfigurationChangeListener
+ *
+ * @author igor
+ */
+public interface IMavenConfigurationChangeListener {
+
+ public void mavenConfigutationChange(MavenConfigurationChangeEvent event) throws CoreException;
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenLauncherConfiguration.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenLauncherConfiguration.java
new file mode 100644
index 00000000..7b6526ec
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenLauncherConfiguration.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+/**
+ * Receive notification of content of plexus configuration.
+ *
+ * @author Igor Fedorenko
+ *
+ * @see MavenRuntime#createLauncherConfiguration
+ */
+public interface IMavenLauncherConfiguration {
+
+ /**
+ * Special realm name used for launcher classpath entries.
+ */
+ public static final String LAUNCHER_REALM = "]laucnher"; //$NON-NLS-1$
+
+ public void setMainType(String type, String realm);
+
+ public void addRealm(String realm);
+
+ public void addProjectEntry(IMavenProjectFacade facade);
+
+ public void addArchiveEntry(String entry) throws CoreException;
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ISettingsChangeListener.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ISettingsChangeListener.java
new file mode 100644
index 00000000..1fb0af01
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ISettingsChangeListener.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.apache.maven.settings.Settings;
+
+/**
+ * ISettingsChangeListener
+ *
+ * @author igor
+ */
+public interface ISettingsChangeListener {
+
+ public void settingsChanged(Settings settings) throws CoreException;
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenConfigurationChangeEvent.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenConfigurationChangeEvent.java
new file mode 100644
index 00000000..323a53a5
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenConfigurationChangeEvent.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
+
+/**
+ * MavenConfigurationChangeEvent
+ *
+ * @author igor
+ */
+public class MavenConfigurationChangeEvent implements MavenPreferenceConstants {
+
+ public static final String P_USER_SETTINGS_FILE = MavenPreferenceConstants.P_USER_SETTINGS_FILE;
+
+ private final String key;
+ private final Object newValue;
+ private final Object oldValue;
+
+ public MavenConfigurationChangeEvent(String key, Object newValue, Object oldValue) {
+ this.key = key;
+ // TODO Auto-generated constructor stub
+ this.newValue = newValue;
+ this.oldValue = oldValue;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public Object getNewValue() {
+ return newValue;
+ }
+
+ public Object getOldValue() {
+ return oldValue;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenModelManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenModelManager.java
new file mode 100644
index 00000000..100d0716
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenModelManager.java
@@ -0,0 +1,581 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.osgi.util.NLS;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.model.DependencyManagement;
+import org.apache.maven.project.MavenProject;
+
+import org.sonatype.aether.artifact.ArtifactTypeRegistry;
+import org.sonatype.aether.collection.CollectRequest;
+import org.sonatype.aether.collection.DependencyCollectionException;
+import org.sonatype.aether.collection.DependencyGraphTransformer;
+import org.sonatype.aether.graph.DependencyNode;
+import org.sonatype.aether.util.DefaultRepositorySystemSession;
+import org.sonatype.aether.util.filter.ScopeDependencyFilter;
+import org.sonatype.aether.util.graph.CloningDependencyVisitor;
+import org.sonatype.aether.util.graph.FilteringDependencyVisitor;
+import org.sonatype.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
+import org.sonatype.aether.util.graph.transformer.JavaEffectiveScopeCalculator;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.model.edit.pom.Build;
+import org.eclipse.m2e.model.edit.pom.Configuration;
+import org.eclipse.m2e.model.edit.pom.Dependency;
+import org.eclipse.m2e.model.edit.pom.Exclusion;
+import org.eclipse.m2e.model.edit.pom.Model;
+import org.eclipse.m2e.model.edit.pom.Plugin;
+import org.eclipse.m2e.model.edit.pom.PomFactory;
+import org.eclipse.m2e.model.edit.pom.util.PomResourceFactoryImpl;
+import org.eclipse.m2e.model.edit.pom.util.PomResourceImpl;
+
+
+/**
+ * Model manager used to read and and modify Maven models
+ *
+ * @author Eugene Kuleshov
+ *
+ * XXX fix circular dependency
+ */
+public class MavenModelManager {
+
+ static final PomFactory POM_FACTORY = PomFactory.eINSTANCE;
+
+ private final MavenProjectManager projectManager;
+
+ private final MavenConsole console;
+
+ private final IMaven maven;
+
+ public MavenModelManager(IMaven maven, MavenProjectManager projectManager, MavenConsole console) {
+ this.maven = maven;
+ this.projectManager = projectManager;
+ this.console = console;
+ }
+
+ public PomResourceImpl loadResource(IFile pomFile) throws CoreException {
+ String path = pomFile.getFullPath().toOSString();
+ URI uri = URI.createPlatformResourceURI(path, true);
+
+ try {
+ Resource resource = new PomResourceFactoryImpl().createResource(uri);
+ resource.load(new HashMap());
+ return (PomResourceImpl)resource;
+
+ } catch(Exception ex) {
+ String msg = NLS.bind(Messages.MavenModelManager_error_cannot_load, pomFile);
+ MavenLogger.log(msg, ex);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, msg, ex));
+ }
+ }
+
+ public org.apache.maven.model.Model readMavenModel(InputStream reader) throws CoreException {
+ return maven.readModel(reader);
+ }
+
+ public org.apache.maven.model.Model readMavenModel(File pomFile) throws CoreException {
+ return maven.readModel(pomFile);
+ }
+
+ public org.apache.maven.model.Model readMavenModel(IFile pomFile) throws CoreException {
+ return maven.readModel(pomFile.getLocation().toFile());
+ }
+
+ public void createMavenModel(IFile pomFile, org.apache.maven.model.Model model) throws CoreException {
+ String pomFileName = pomFile.getLocation().toString();
+ if(pomFile.exists()) {
+ String msg = NLS.bind(Messages.MavenModelManager_error_pom_exists, pomFileName);
+ console.logError(msg);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, msg, null));
+ }
+
+ try {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+
+ maven.writeModel(model, buf);
+
+ // XXX MNGECLIPSE-495
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ documentBuilderFactory.setNamespaceAware(false);
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+
+ Document document = documentBuilder.parse(new ByteArrayInputStream(buf.toByteArray()));
+ Element documentElement = document.getDocumentElement();
+
+ NamedNodeMap attributes = documentElement.getAttributes();
+
+ if(attributes == null || attributes.getNamedItem("xmlns") == null) { //$NON-NLS-1$
+ Attr attr = document.createAttribute("xmlns"); //$NON-NLS-1$
+ attr.setTextContent("http://maven.apache.org/POM/4.0.0"); //$NON-NLS-1$
+ documentElement.setAttributeNode(attr);
+ }
+
+ if(attributes == null || attributes.getNamedItem("xmlns:xsi") == null) { //$NON-NLS-1$
+ Attr attr = document.createAttribute("xmlns:xsi"); //$NON-NLS-1$
+ attr.setTextContent("http://www.w3.org/2001/XMLSchema-instance"); //$NON-NLS-1$
+ documentElement.setAttributeNode(attr);
+ }
+
+ if(attributes == null || attributes.getNamedItem("xsi:schemaLocation") == null) { //$NON-NLS-1$
+ Attr attr = document.createAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation"); //$NON-NLS-1$ //$NON-NLS-2$
+ attr.setTextContent("http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"); //$NON-NLS-1$
+ documentElement.setAttributeNode(attr);
+ }
+
+ TransformerFactory transfac = TransformerFactory.newInstance();
+ Transformer trans = transfac.newTransformer();
+ trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); //$NON-NLS-1$
+
+ buf.reset();
+ trans.transform(new DOMSource(document), new StreamResult(buf));
+
+ pomFile.create(new ByteArrayInputStream(buf.toByteArray()), true, new NullProgressMonitor());
+
+ } catch(RuntimeException ex) {
+ String msg = NLS.bind(Messages.MavenModelManager_error_create, pomFileName, ex.toString());
+ console.logError(msg);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, msg, ex));
+ } catch(Exception ex) {
+ String msg = NLS.bind(Messages.MavenModelManager_error_create, pomFileName, ex.toString());
+ console.logError(msg);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, msg, ex));
+ }
+ }
+
+ public synchronized DependencyNode readDependencyTree(IFile file, String classpath,
+ IProgressMonitor monitor) throws CoreException {
+ monitor.setTaskName(Messages.MavenModelManager_monitor_reading);
+ MavenProject mavenProject = readMavenProject(file, monitor);
+
+ return readDependencyTree(mavenProject, classpath, monitor);
+ }
+
+ public synchronized DependencyNode readDependencyTree(MavenProject mavenProject,
+ String classpath, IProgressMonitor monitor) throws CoreException {
+ monitor.setTaskName(Messages.MavenModelManager_monitor_building);
+
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+ DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(maven.createSession(
+ maven.createExecutionRequest(monitor), mavenProject).getRepositorySession());
+
+ DependencyGraphTransformer transformer = new ChainedDependencyGraphTransformer(new JavaEffectiveScopeCalculator(),
+ new NearestVersionConflictResolver());
+ session.setDependencyGraphTransformer(transformer);
+
+ ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(maven.getProjectRealm(mavenProject));
+
+ ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
+
+ CollectRequest request = new CollectRequest();
+ request.setRequestContext("project"); //$NON-NLS-1$
+ request.setRepositories(mavenProject.getRemoteProjectRepositories());
+
+ for(org.apache.maven.model.Dependency dependency : mavenProject.getDependencies()) {
+ request.addDependency(RepositoryUtils.toDependency(dependency, stereotypes));
+ }
+
+ DependencyManagement depMngt = mavenProject.getDependencyManagement();
+ if(depMngt != null) {
+ for(org.apache.maven.model.Dependency dependency : depMngt.getDependencies()) {
+ request.addManagedDependency(RepositoryUtils.toDependency(dependency, stereotypes));
+ }
+ }
+
+ DependencyNode node;
+ try {
+ node = MavenPlugin.getDefault().getRepositorySystem().collectDependencies(session, request).getRoot();
+ } catch(DependencyCollectionException ex) {
+ String msg = Messages.MavenModelManager_error_read;
+ MavenLogger.log(msg, ex);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, msg, ex));
+ }
+
+ Collection<String> scopes = new HashSet<String>();
+ Collections.addAll(scopes, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED,
+ Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST);
+ if(Artifact.SCOPE_COMPILE.equals(classpath)) {
+ scopes.remove(Artifact.SCOPE_COMPILE);
+ scopes.remove(Artifact.SCOPE_SYSTEM);
+ scopes.remove(Artifact.SCOPE_PROVIDED);
+ } else if(Artifact.SCOPE_RUNTIME.equals(classpath)) {
+ scopes.remove(Artifact.SCOPE_COMPILE);
+ scopes.remove(Artifact.SCOPE_RUNTIME);
+ } else if(Artifact.SCOPE_COMPILE_PLUS_RUNTIME.equals(classpath)) {
+ scopes.remove(Artifact.SCOPE_COMPILE);
+ scopes.remove(Artifact.SCOPE_SYSTEM);
+ scopes.remove(Artifact.SCOPE_PROVIDED);
+ scopes.remove(Artifact.SCOPE_RUNTIME);
+ } else {
+ scopes.clear();
+ }
+
+ CloningDependencyVisitor cloner = new CloningDependencyVisitor();
+ node.accept(new FilteringDependencyVisitor(cloner, new ScopeDependencyFilter(null, scopes)));
+ node = cloner.getRootNode();
+
+ return node;
+ } finally {
+ Thread.currentThread().setContextClassLoader(oldClassLoader);
+ }
+ }
+
+ public MavenProject readMavenProject(IFile file, IProgressMonitor monitor) throws CoreException {
+ IMavenProjectFacade projectFacade = projectManager.create(file, true, monitor);
+ MavenProject mavenProject = projectFacade.getMavenProject(monitor);
+ return mavenProject;
+ }
+
+// public ProjectDocument readProjectDocument(IFile pomFile) throws CoreException {
+// String name = pomFile.getProject().getName() + "/" + pomFile.getProjectRelativePath();
+// try {
+// return ProjectDocument.Factory.parse(pomFile.getLocation().toFile(), getXmlOptions());
+// } catch(XmlException ex) {
+// String msg = "Unable to parse " + name;
+// console.logError(msg + "; " + ex.toString());
+// throw new CoreException(new Status(IStatus.ERROR, MavenPlugin.PLUGIN_ID, -1, msg, ex));
+// } catch(IOException ex) {
+// String msg = "Unable to read " + name;
+// console.logError(msg + "; " + ex.toString());
+// throw new CoreException(new Status(IStatus.ERROR, MavenPlugin.PLUGIN_ID, -1, msg, ex));
+// }
+// }
+//
+// public ProjectDocument readProjectDocument(File pom) throws CoreException {
+// try {
+// return ProjectDocument.Factory.parse(pom, getXmlOptions());
+// } catch(XmlException ex) {
+// String msg = "Unable to parse " + pom.getAbsolutePath();
+// console.logError(msg + "; " + ex.toString());
+// throw new CoreException(new Status(IStatus.ERROR, MavenPlugin.PLUGIN_ID, -1, msg, ex));
+// } catch(IOException ex) {
+// String msg = "Unable to read " + pom.getAbsolutePath();
+// console.logError(msg + "; " + ex.toString());
+// throw new CoreException(new Status(IStatus.ERROR, MavenPlugin.PLUGIN_ID, -1, msg, ex));
+// }
+// }
+
+ public void updateProject(IFile pomFile, ProjectUpdater updater) {
+ File pom = pomFile.getLocation().toFile();
+ PomResourceImpl resource = null;
+ try {
+ resource = loadResource(pomFile);
+ updater.update(resource.getModel());
+ resource.save(Collections.EMPTY_MAP);
+ } catch(Exception ex) {
+ String msg = "Unable to update " + pom;
+ console.logError(msg + "; " + ex.getMessage()); //$NON-NLS-1$
+ MavenLogger.log(msg, ex);
+ } finally {
+ if (resource != null) {
+ resource.unload();
+ }
+ }
+ }
+
+ public void addDependency(IFile pomFile, org.apache.maven.model.Dependency dependency) {
+ updateProject(pomFile, new DependencyAdder(dependency));
+ }
+
+ public void addModule(IFile pomFile, final String moduleName) {
+ updateProject(pomFile, new ModuleAdder(moduleName));
+ }
+
+// /**
+// * Project updater for adding Maven namespace declaration
+// */
+// public static class NamespaceAdder extends ProjectUpdater {
+//
+// public void update(Model model) {
+// DocumentRoot documentRoot = PomFactory.eINSTANCE.createDocumentRoot();
+// EMap<String, String> prefixMap = documentRoot.getXMLNSPrefixMap();
+// EMap<String, String> schemaLocation = documentRoot.getXSISchemaLocation();
+//
+// // xmlns="http://maven.apache.org/POM/4.0.0"
+// // xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+// // xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+//
+//// XmlCursor cursor = project.newCursor();
+//// cursor.toNextToken();
+//// if(!cursor.toFirstAttribute()) {
+//// cursor.toNextToken();
+//// }
+////
+//// String uri = ProjectDocument.type.getDocumentElementName().getNamespaceURI();
+//// cursor.insertNamespace("", uri);
+//// cursor.insertNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
+//// cursor.insertAttributeWithValue( //
+//// new QName("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation", "xsi"), uri
+//// + " http://maven.apache.org/xsd/maven-4.0.0.xsd");
+// }
+//
+// }
+
+ /**
+ * Project updater for adding dependencies
+ */
+ public static class DependencyAdder extends ProjectUpdater {
+
+ private final org.apache.maven.model.Dependency dependency;
+
+ public DependencyAdder(org.apache.maven.model.Dependency dependency) {
+ this.dependency = dependency;
+ }
+
+ public void update(org.eclipse.m2e.model.edit.pom.Model model) {
+ Dependency dependency = POM_FACTORY.createDependency();
+
+ dependency.setGroupId(this.dependency.getGroupId());
+ dependency.setArtifactId(this.dependency.getArtifactId());
+
+ if(this.dependency.getVersion()!=null) {
+ dependency.setVersion(this.dependency.getVersion());
+ }
+
+ if(this.dependency.getClassifier() != null) {
+ dependency.setClassifier(this.dependency.getClassifier());
+ }
+
+ if(this.dependency.getType() != null //
+ && !"jar".equals(this.dependency.getType()) // //$NON-NLS-1$
+ && !"null".equals(this.dependency.getType())) { // guard against MNGECLIPSE-622 //$NON-NLS-1$
+ dependency.setType(this.dependency.getType());
+ }
+
+ if(this.dependency.getScope() != null && !"compile".equals(this.dependency.getScope())) { //$NON-NLS-1$
+ dependency.setScope(this.dependency.getScope());
+ }
+
+ if(this.dependency.getSystemPath() != null) {
+ dependency.setSystemPath(this.dependency.getSystemPath());
+ }
+
+ if(this.dependency.isOptional()) {
+ dependency.setOptional("true"); //$NON-NLS-1$
+ }
+
+ if(!this.dependency.getExclusions().isEmpty()) {
+
+ Iterator<org.apache.maven.model.Exclusion> it = this.dependency.getExclusions().iterator();
+ while(it.hasNext()) {
+ org.apache.maven.model.Exclusion e = it.next();
+ Exclusion exclusion = POM_FACTORY.createExclusion();
+ exclusion.setGroupId(e.getGroupId());
+ exclusion.setArtifactId(e.getArtifactId());
+ dependency.getExclusions().add(exclusion);
+ }
+ }
+
+ // search for dependency with same GAC and remove if found
+ Iterator<Dependency> it = model.getDependencies().iterator();
+ boolean mergeScope = false;
+ String oldScope = Artifact.SCOPE_COMPILE;
+ while (it.hasNext()) {
+ Dependency dep = it.next();
+ if (dep.getGroupId().equals(dependency.getGroupId()) &&
+ dep.getArtifactId().equals(dependency.getArtifactId()) &&
+ compareNulls(dep.getClassifier(), dependency.getClassifier())) {
+ oldScope = dep.getScope();
+ it.remove();
+ mergeScope = true;
+ }
+ }
+
+ if (mergeScope) {
+ // merge scopes
+ if (oldScope == null) {
+ oldScope = Artifact.SCOPE_COMPILE;
+ }
+
+ String newScope = this.dependency.getScope();
+ if (newScope == null) {
+ newScope = Artifact.SCOPE_COMPILE;
+ }
+
+ if (!oldScope.equals(newScope)) {
+ boolean systemScope = false;
+ boolean providedScope = false;
+ boolean compileScope = false;
+ boolean runtimeScope = false;
+ boolean testScope = false;
+
+ // test old scope
+ if ( Artifact.SCOPE_COMPILE.equals( oldScope ) ) {
+ systemScope = true;
+ providedScope = true;
+ compileScope = true;
+ runtimeScope = false;
+ testScope = false;
+ } else if ( Artifact.SCOPE_RUNTIME.equals( oldScope ) ) {
+ systemScope = false;
+ providedScope = false;
+ compileScope = true;
+ runtimeScope = true;
+ testScope = false;
+ } else if ( Artifact.SCOPE_TEST.equals( oldScope ) ) {
+ systemScope = true;
+ providedScope = true;
+ compileScope = true;
+ runtimeScope = true;
+ testScope = true;
+ }
+
+ // merge with new one
+ if ( Artifact.SCOPE_COMPILE.equals( newScope ) ) {
+ systemScope = systemScope || true;
+ providedScope = providedScope || true;
+ compileScope = compileScope || true;
+ runtimeScope = runtimeScope || false;
+ testScope = testScope || false;
+ } else if ( Artifact.SCOPE_RUNTIME.equals( newScope ) ) {
+ systemScope = systemScope || false;
+ providedScope = providedScope || false;
+ compileScope = compileScope || true;
+ runtimeScope = runtimeScope || true;
+ testScope = testScope || false;
+ } else if ( Artifact.SCOPE_TEST.equals( newScope ) ) {
+ systemScope = systemScope || true;
+ providedScope = providedScope || true;
+ compileScope = compileScope || true;
+ runtimeScope = runtimeScope || true;
+ testScope = testScope || true;
+ }
+
+ if (testScope) {
+ newScope = Artifact.SCOPE_TEST;
+ } else if (runtimeScope) {
+ newScope = Artifact.SCOPE_RUNTIME;
+ } else if (compileScope) {
+ newScope = Artifact.SCOPE_COMPILE;
+ } else {
+ // unchanged
+ }
+
+ dependency.setScope(newScope);
+ }
+ }
+
+ model.getDependencies().add(dependency);
+ }
+
+ @SuppressWarnings("null")
+ private boolean compareNulls(String s1, String s2) {
+ if (s1 == null && s2 == null) {
+ return true;
+ }
+ if ((s1 == null && s2 != null) || (s2 == null && s1 != null)) {
+ return false;
+ }
+ return s1.equals(s2);
+ }
+ }
+
+
+ /**
+ * Project updater for adding modules
+ */
+ public static class ModuleAdder extends ProjectUpdater {
+
+ private final String moduleName;
+
+ public ModuleAdder(String moduleName) {
+ this.moduleName = moduleName;
+ }
+
+ public void update(Model model) {
+ model.getModules().add(moduleName);
+ }
+ }
+
+ /**
+ * Project updater for adding plugins
+ */
+ public static class PluginAdder extends ProjectUpdater {
+
+ private final String groupId;
+ private final String artifactId;
+ private final String version;
+
+ public PluginAdder(String groupId, String artifactId, String version) {
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.version = version;
+ }
+
+ public void update(Model model) {
+ Build build = model.getBuild();
+ if(build==null) {
+ build = POM_FACTORY.createBuild();
+ model.setBuild(build);
+ }
+
+ Plugin plugin = POM_FACTORY.createPlugin();
+
+ if(!"org.apache.maven.plugins".equals(this.groupId)) { //$NON-NLS-1$
+ plugin.setGroupId(this.groupId);
+ }
+
+ plugin.setArtifactId(this.artifactId);
+
+ if(this.version != null) {
+ plugin.setVersion(this.version);
+ }
+
+ Configuration configuration = POM_FACTORY.createConfiguration();
+ plugin.setConfiguration(configuration);
+
+ build.getPlugins().add(plugin);
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenRuntime.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenRuntime.java
new file mode 100644
index 00000000..31940164
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenRuntime.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Maven runtime
+ *
+ * @author Eugene Kuleshov
+ * @author Igor Fedorenko
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface MavenRuntime {
+
+ public abstract boolean isEditable();
+
+ /**
+ * Reads m2.conf file and notifies configuration collector of the logical content of plexus configuration.
+ *
+ * Collector callback methods are invoked in the order corresponding
+ * configuration elements are present in m2.conf file.
+ */
+ public abstract void createLauncherConfiguration(IMavenLauncherConfiguration collector, IProgressMonitor monitor) throws CoreException;
+
+ public abstract String getLocation();
+
+ public abstract String getSettings();
+
+ public abstract boolean isAvailable();
+
+ public String getVersion();
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenRuntimeManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenRuntimeManager.java
new file mode 100644
index 00000000..0fd11501
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenRuntimeManager.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+
+import org.eclipse.m2e.core.internal.embedder.MavenEmbeddedRuntime;
+import org.eclipse.m2e.core.internal.embedder.MavenExternalRuntime;
+import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
+
+/**
+ * Maven runtime manager
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenRuntimeManager {
+
+ public static final String DEFAULT = "DEFAULT"; //$NON-NLS-1$
+
+ public static final String EMBEDDED = "EMBEDDED"; //$NON-NLS-1$
+
+ public static final String WORKSPACE = "WORKSPACE"; //$NON-NLS-1$
+
+ private final IPreferenceStore preferenceStore;
+
+ private Map<String, MavenRuntime> runtimes = new LinkedHashMap<String, MavenRuntime>();
+
+ private MavenRuntime embeddedRuntime;
+
+ private MavenRuntime workspaceRuntime;
+
+ private MavenRuntime defaultRuntime;
+
+
+ public MavenRuntimeManager(IPreferenceStore preferenceStore) {
+ this.preferenceStore = preferenceStore;
+ initRuntimes();
+ }
+
+ public void setEmbeddedRuntime(MavenRuntime embeddedRuntime) {
+ this.embeddedRuntime = embeddedRuntime;
+ }
+
+ public void setWorkspaceRuntime(MavenRuntime workspaceRuntime) {
+ this.workspaceRuntime = workspaceRuntime;
+ }
+
+ public MavenRuntime getDefaultRuntime() {
+ if(defaultRuntime == null || !defaultRuntime.isAvailable()) {
+ return embeddedRuntime;
+ }
+ return this.defaultRuntime;
+ }
+
+ public MavenRuntime getRuntime(String location) {
+ if(location==null || location.length()==0 || DEFAULT.equals(location)) {
+ return getDefaultRuntime();
+ }
+ if(EMBEDDED.equals(location)) {
+ return embeddedRuntime;
+ }
+ if(WORKSPACE.equals(location)) {
+ return workspaceRuntime;
+ }
+ return runtimes.get(location);
+ }
+
+ public List<MavenRuntime> getMavenRuntimes() {
+ ArrayList<MavenRuntime> runtimes = new ArrayList<MavenRuntime>();
+
+ runtimes.add(embeddedRuntime);
+
+ if(workspaceRuntime != null && workspaceRuntime.isAvailable()) {
+ runtimes.add(workspaceRuntime);
+ }
+
+ for(MavenRuntime runtime : this.runtimes.values()) {
+ if(runtime.isAvailable()) {
+ runtimes.add(runtime);
+ }
+ }
+ return runtimes;
+ }
+
+ public void reset() {
+ preferenceStore.setToDefault(MavenPreferenceConstants.P_RUNTIMES);
+ preferenceStore.setToDefault(MavenPreferenceConstants.P_DEFAULT_RUNTIME);
+
+ initRuntimes();
+ }
+
+ public void setDefaultRuntime(MavenRuntime runtime) {
+ this.defaultRuntime = runtime;
+
+ if(runtime == null) {
+ preferenceStore.setToDefault(MavenPreferenceConstants.P_DEFAULT_RUNTIME);
+ } else {
+ preferenceStore.setValue(MavenPreferenceConstants.P_DEFAULT_RUNTIME, runtime.getLocation());
+ }
+ }
+
+ public void setRuntimes(List<MavenRuntime> runtimes) {
+ this.runtimes.clear();
+
+ String separator = ""; //$NON-NLS-1$
+ StringBuffer sb = new StringBuffer();
+ for(MavenRuntime runtime : runtimes) {
+ if(runtime.isEditable()) {
+ this.runtimes.put(runtime.getLocation(), runtime);
+ sb.append(separator).append(runtime.getLocation());
+ separator = "|"; //$NON-NLS-1$
+ }
+ }
+ preferenceStore.setValue(MavenPreferenceConstants.P_RUNTIMES, sb.toString());
+ }
+
+ private void initRuntimes() {
+ runtimes.clear();
+
+ defaultRuntime = null;
+
+ String selected = preferenceStore.getString(MavenPreferenceConstants.P_DEFAULT_RUNTIME);
+
+ String runtimesPreference = preferenceStore.getString(MavenPreferenceConstants.P_RUNTIMES);
+ if(runtimesPreference!=null && runtimesPreference.length()>0) {
+ String[] locations = runtimesPreference.split("\\|"); //$NON-NLS-1$
+ for(int i = 0; i < locations.length; i++ ) {
+ MavenRuntime runtime = createExternalRuntime(locations[i]);
+ runtimes.put(runtime.getLocation(), runtime);
+ if(runtime.getLocation().equals(selected)) {
+ defaultRuntime = runtime;
+ }
+ }
+ }
+ }
+
+ public static MavenRuntime createExternalRuntime(String location) {
+ return new MavenExternalRuntime(location);
+ }
+
+ public String getGlobalSettingsFile() {
+ //only return the preference store value for the global settings file if its an embedded runtime
+ if(defaultRuntime == null || defaultRuntime instanceof MavenEmbeddedRuntime){
+ String globalSettings = preferenceStore.getString(MavenPreferenceConstants.P_GLOBAL_SETTINGS_FILE);
+ return globalSettings.trim().length()==0 ? null : globalSettings;
+ }
+ return defaultRuntime == null ? null : defaultRuntime.getSettings();
+ }
+
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/NearestVersionConflictResolver.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/NearestVersionConflictResolver.java
new file mode 100644
index 00000000..4e24efe3
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/NearestVersionConflictResolver.java
@@ -0,0 +1,257 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import org.sonatype.aether.RepositoryException;
+import org.sonatype.aether.collection.DependencyGraphTransformationContext;
+import org.sonatype.aether.collection.DependencyGraphTransformer;
+import org.sonatype.aether.collection.UnsolvableVersionConflictException;
+import org.sonatype.aether.graph.DependencyNode;
+import org.sonatype.aether.util.graph.DefaultDependencyNode;
+import org.sonatype.aether.util.graph.transformer.ConflictIdSorter;
+import org.sonatype.aether.util.graph.transformer.TransformationContextKeys;
+import org.sonatype.aether.version.Version;
+import org.sonatype.aether.version.VersionConstraint;
+
+
+class NearestVersionConflictResolver implements DependencyGraphTransformer {
+
+ public DependencyNode transformGraph(DependencyNode node, DependencyGraphTransformationContext context)
+ throws RepositoryException {
+ List<?> sortedConflictIds = (List<?>) context.get(TransformationContextKeys.SORTED_CONFLICT_IDS);
+ if(sortedConflictIds == null) {
+ ConflictIdSorter sorter = new ConflictIdSorter();
+ sorter.transformGraph(node, context);
+
+ sortedConflictIds = (List<?>) context.get(TransformationContextKeys.SORTED_CONFLICT_IDS);
+ }
+
+ Map<?, ?> conflictIds = (Map<?, ?>) context.get(TransformationContextKeys.CONFLICT_IDS);
+ if(conflictIds == null) {
+ throw new RepositoryException("conflict groups have not been identified");
+ }
+
+ Map<DependencyNode, Integer> depths = new IdentityHashMap<DependencyNode, Integer>(conflictIds.size());
+ for(Object key : sortedConflictIds) {
+ ConflictGroup group = new ConflictGroup(key);
+ depths.clear();
+ selectVersion(node, null, 0, depths, group, conflictIds);
+ pruneNonSelectedVersions(group, conflictIds);
+ }
+
+ return node;
+ }
+
+ private void selectVersion(DependencyNode node, DependencyNode parent, int depth,
+ Map<DependencyNode, Integer> depths, ConflictGroup group, Map<?, ?> conflictIds) throws RepositoryException {
+ Integer smallestDepth = depths.get(node);
+ if(smallestDepth == null || smallestDepth.intValue() > depth) {
+ depths.put(node, Integer.valueOf(depth));
+ } else {
+ return;
+ }
+
+ Object key = conflictIds.get(node);
+ if(group.key.equals(key)) {
+ Position pos = new Position(parent, depth);
+ if(parent != null) {
+ group.positions.add(pos);
+ }
+
+ if(!group.isAcceptable(node.getVersion())) {
+ return;
+ }
+
+ group.candidates.put(node, pos);
+
+ if(!node.getVersionConstraint().getRanges().isEmpty()) {
+ group.constraints.add(node.getVersionConstraint());
+ }
+
+ if(group.version == null || isNearer(pos, node.getVersion(), group.position, group.version)) {
+ group.winner = node;
+ group.version = node.getVersion();
+ group.position = pos;
+ }
+
+ if(!group.isAcceptable(group.version)) {
+ group.winner = null;
+ group.version = null;
+
+ for(Iterator<Map.Entry<DependencyNode, Position>> it = group.candidates.entrySet().iterator(); it.hasNext();) {
+ Map.Entry<DependencyNode, Position> entry = it.next();
+ Version version = entry.getKey().getVersion();
+ pos = entry.getValue();
+
+ if(!group.isAcceptable(version)) {
+ it.remove();
+ } else if(group.version == null || isNearer(pos, version, group.position, group.version)) {
+ group.winner = entry.getKey();
+ group.version = version;
+ group.position = pos;
+ }
+ }
+
+ if(group.version == null) {
+ Collection<String> versions = new LinkedHashSet<String>();
+ for(VersionConstraint constraint : group.constraints) {
+ versions.add(constraint.toString());
+ }
+ throw new UnsolvableVersionConflictException(group.key, versions);
+ }
+ }
+ }
+
+ depth++ ;
+
+ for(DependencyNode child : node.getChildren()) {
+ selectVersion(child, node, depth, depths, group, conflictIds);
+ }
+ }
+
+ private boolean isNearer(Position pos1, Version ver1, Position pos2, Version ver2) {
+ if(pos1.depth < pos2.depth) {
+ return true;
+ } else if(pos1.depth == pos2.depth && pos1.parent == pos2.parent && ver1.compareTo(ver2) > 0) {
+ return true;
+ }
+ return false;
+ }
+
+ private void pruneNonSelectedVersions(ConflictGroup group, Map<?, ?> conflictIds) {
+ for(Position pos : group.positions) {
+ ConflictNode conflictNode = null;
+
+ for(ListIterator<DependencyNode> it = pos.parent.getChildren().listIterator(); it.hasNext();) {
+ DependencyNode child = it.next();
+
+ Object key = conflictIds.get(child);
+
+ if(group.key.equals(key)) {
+ if(!group.pruned && group.position.depth == pos.depth && group.version.equals(child.getVersion())) {
+ group.pruned = true;
+ } else if(pos.equals(group.position)) {
+ it.remove();
+ } else if(conflictNode == null) {
+ conflictNode = new ConflictNode(child, group.winner);
+ it.set(conflictNode);
+ } else {
+ it.remove();
+
+ if(conflictNode.getVersion().compareTo(child.getVersion()) < 0) {
+ conflictNode.setDependency(child.getDependency());
+ conflictNode.setVersion(child.getVersion());
+ conflictNode.setVersionConstraint(child.getVersionConstraint());
+ conflictNode.setPremanagedVersion(child.getPremanagedVersion());
+ conflictNode.setRelocations(child.getRelocations());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static final class ConflictGroup {
+
+ final Object key;
+
+ final Collection<VersionConstraint> constraints = new HashSet<VersionConstraint>();
+
+ final Map<DependencyNode, Position> candidates = new IdentityHashMap<DependencyNode, Position>(32);
+
+ DependencyNode winner;
+
+ Version version;
+
+ Position position;
+
+ final Collection<Position> positions = new LinkedHashSet<Position>();
+
+ boolean pruned;
+
+ public ConflictGroup(Object key) {
+ this.key = key;
+ this.position = new Position(null, Integer.MAX_VALUE);
+ }
+
+ boolean isAcceptable(Version version) {
+ for(VersionConstraint constraint : constraints) {
+ if(!constraint.containsVersion(version)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return key + " > " + version; //$NON-NLS-1$
+ }
+
+ }
+
+ static final class Position {
+
+ final DependencyNode parent;
+
+ final int depth;
+
+ final int hash;
+
+ public Position(DependencyNode parent, int depth) {
+ this.parent = parent;
+ this.depth = depth;
+ hash = 31 * System.identityHashCode(parent) + depth;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(this == obj) {
+ return true;
+ } else if(!(obj instanceof Position)) {
+ return false;
+ }
+ Position that = (Position) obj;
+ return this.parent == that.parent && this.depth == that.depth;
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return depth + " > " + parent; //$NON-NLS-1$
+ }
+
+ }
+
+ static final class ConflictNode extends DefaultDependencyNode {
+
+ public ConflictNode(DependencyNode node, DependencyNode related) {
+ super(node);
+ setAliases(Collections.singletonList(related.getDependency().getArtifact()));
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ProjectUpdater.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ProjectUpdater.java
new file mode 100644
index 00000000..42fbf301
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/ProjectUpdater.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.embedder;
+
+import org.eclipse.m2e.model.edit.pom.Model;
+
+/**
+ * Project updater
+ *
+ * @author Eugene Kuleshov
+ */
+public abstract class ProjectUpdater {
+
+ public abstract void update(Model model);
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IIndex.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IIndex.java
new file mode 100644
index 00000000..0add0fd5
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IIndex.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+
+/**
+ * @author igor
+ */
+public interface IIndex {
+
+ // search keys
+
+ public static final String SEARCH_GROUP = "groupId"; //$NON-NLS-1$
+
+ public static final String SEARCH_ARTIFACT = "artifact"; //$NON-NLS-1$
+
+ public static final String SEARCH_PLUGIN = "plugin"; //$NON-NLS-1$
+
+ public static final String SEARCH_ARCHETYPE = "archetype"; //$NON-NLS-1$
+
+ public static final String SEARCH_PACKAGING = "packaging"; //$NON-NLS-1$
+
+ public static final String SEARCH_SHA1 = "sha1"; //$NON-NLS-1$
+
+ /**
+ * like SEARCH_ARTIFACT but will only return artifacts with packaging == pom
+ */
+ public static final String SEARCH_PARENTS = "parents"; //$NON-NLS-1$
+
+ // search classifiers
+
+// public enum SearchClassifiers {
+// JARS,
+//
+// JAVADOCS,
+//
+// SOURCES,
+//
+// TESTS
+// }
+//
+// public Set<SearchClassifiers> ALL_CLASSIFIERS = new HashSet<IIndex.SearchClassifiers>(Arrays.asList(SearchClassifiers
+// .values()));
+
+ //
+
+ public static final int SEARCH_JARS = 1 << 0;
+
+ public static final int SEARCH_JAVADOCS = 1 << 1;
+
+ public static final int SEARCH_SOURCES = 1 << 2;
+
+ public static final int SEARCH_TESTS = 1 << 3;
+
+ public static final int SEARCH_ALL = 15;
+
+ // availability flags
+
+ public static final int PRESENT = 1;
+
+ public static final int NOT_PRESENT = 0;
+
+ public static final int NOT_AVAILABLE = 2;
+
+ // index queries
+
+ public IndexedArtifactFile getIndexedArtifactFile(ArtifactKey artifact) throws CoreException;
+
+ public IndexedArtifactFile identify(File file) throws CoreException;
+
+ /**
+ * Performs a search for artifacts with given parameters.
+ *
+ * @param groupId
+ * @param artifactId
+ * @param version
+ * @param packaging
+ * @return
+ * @throws CoreException
+ */
+ public Collection<IndexedArtifact> find(SearchExpression groupId, SearchExpression artifactId,
+ SearchExpression version, SearchExpression packaging) throws CoreException;
+
+ /**
+ * Performs a search for artifacts with given parameters. Similar to
+ * {@link IIndex#find(SearchExpression, SearchExpression, SearchExpression, SearchExpression)}, but here you are able
+ * to pass in multiple values for all searches. All elements of collections will form an "OR" of one query.
+ *
+ * @param groupId
+ * @param artifactId
+ * @param version
+ * @param packaging
+ * @return
+ * @throws CoreException
+ */
+ public Collection<IndexedArtifact> find(Collection<SearchExpression> groupId,
+ Collection<SearchExpression> artifactId, Collection<SearchExpression> version,
+ Collection<SearchExpression> packaging) throws CoreException;
+
+ /**
+ * Convenience method to search in all indexes enabled for repositories defined in settings.xml. This method always
+ * performs "scored" search.
+ */
+ public Map<String, IndexedArtifact> search(SearchExpression expression, String searchType) throws CoreException;
+
+ /**
+ * Convenience method to search in all indexes enabled for repositories defined in settings.xml. This method always
+ * performs "scored" search.
+ *
+ * @param term - search term
+ * @param searchType - query type. Should be one of the SEARCH_* values.
+ * @param classifier - the type of classifiers to search for, SEARCH_ALL, SEARCH_JAVADOCS, SEARCH_SOURCES,
+ * SEARCH_TESTS
+ */
+ public Map<String, IndexedArtifact> search(SearchExpression expression, String searchType, int classifier)
+ throws CoreException;
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IMutableIndex.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IMutableIndex.java
new file mode 100644
index 00000000..c6d11b3f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IMutableIndex.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+import java.io.File;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+
+/**
+ * @author igor
+ */
+public interface IMutableIndex extends IIndex {
+
+ // index content manipulation
+
+ public void addArtifact(File pomFile, ArtifactKey artifactKey);
+
+ public void removeArtifact(File pomFile, ArtifactKey artifactKey);
+
+ // reindexing
+
+ public void updateIndex(boolean force, IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexListener.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexListener.java
new file mode 100644
index 00000000..27ac3473
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexListener.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+import org.eclipse.m2e.core.repository.IRepository;
+
+
+
+/**
+ * IndexListener
+ *
+ * @author Eugene Kuleshov
+ */
+public interface IndexListener {
+
+ public void indexAdded(IRepository repository);
+
+ public void indexRemoved(IRepository repository);
+
+ public void indexChanged(IRepository repository);
+
+ public void indexUpdating(IRepository repository);
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexManager.java
new file mode 100644
index 00000000..0dbf701a
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexManager.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+
+
+public interface IndexManager {
+
+ // well-known indexes
+
+ String LOCAL_INDEX = "local"; //$NON-NLS-1$
+
+ String WORKSPACE_INDEX = "workspace"; //$NON-NLS-1$
+
+ //
+
+ IMutableIndex getWorkspaceIndex();
+
+ IMutableIndex getLocalIndex();
+
+ /**
+ * For Maven projects, returns index of all repositories configured for the project. Index includes repositories
+ * defined in the project pom.xml, inherited from parent projects and defined in enabled profiles in settings.xml. If
+ * project is null or is not a maven project, returns index that includes repositories defined in profiles enabled by
+ * default in settings.xml.
+ */
+ IIndex getIndex(IProject project) throws CoreException;
+
+ /**
+ * Returns index aggregating all indexes enabled for repositories defined in settings.xml
+ *
+ * @return
+ * @throws CoreException
+ */
+ IIndex getAllIndexes() throws CoreException;
+
+ //
+
+ void removeIndexListener(IndexListener listener);
+
+ void addIndexListener(IndexListener listener);
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexedArtifact.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexedArtifact.java
new file mode 100644
index 00000000..756bcfb8
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexedArtifact.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+
+
+public class IndexedArtifact{
+
+ public static final Comparator<IndexedArtifactFile> FILE_INFO_COMPARATOR = new Comparator<IndexedArtifactFile>() {
+
+ @SuppressWarnings("unchecked")
+ public int compare(IndexedArtifactFile f1, IndexedArtifactFile f2) {
+ ArtifactVersion v1 = f1.getArtifactVersion();
+ ArtifactVersion v2 = f2.getArtifactVersion();
+ int r = -v1.compareTo(v2);
+ if(r!=0) {
+ return r;
+ }
+
+ String c1 = f1.classifier;
+ String c2 = f2.classifier;
+ if(c1 == null) {
+ return c2 == null ? 0 : -1;
+ }
+ if(c2 == null) {
+ return 1;
+ }
+ return c1.compareTo(c2);
+ }
+
+ };
+
+ private final String group;
+
+ private final String artifact;
+
+ private final String packageName;
+
+ private final String className;
+
+ private final String packaging;
+
+ //a non-zero odd-prime hash seed
+ private static final int SEED = 17;
+
+ /**
+ * Set<IndexedArtifactFile>
+ */
+ private final Set<IndexedArtifactFile> files = new TreeSet<IndexedArtifactFile>(FILE_INFO_COMPARATOR);
+
+ public IndexedArtifact(String group, String artifact, String packageName, String className, String packaging) {
+ this.group = group;
+ this.artifact = artifact;
+ this.packageName = packageName;
+ this.className = className;
+ this.packaging = packaging;
+ }
+
+ public void addFile(IndexedArtifactFile indexedArtifactFile) {
+ getFiles().add(indexedArtifactFile);
+ }
+
+ public String getPackageName(){
+ if(packageName != null && packageName.startsWith(".") && packageName.length()>1){ //$NON-NLS-1$
+ return packageName.substring(1);
+ }
+ return packageName;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer("\n" + getClassname() + " " + packageName + " " + getGroupId() + " : " + getArtifactId()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ return sb.toString();
+ }
+
+ public String getGroupId() {
+ return group;
+ }
+
+ public String getArtifactId() {
+ return artifact;
+ }
+
+ public String getPackaging() {
+ return packaging;
+ }
+
+ public String getClassname() {
+ return className;
+ }
+
+ public Set<IndexedArtifactFile> getFiles() {
+ return files;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ int result = SEED;
+ result *= fieldHash(getGroupId());
+ result *= fieldHash(getArtifactId());
+ result *= fieldHash(getPackaging());
+ result *= fieldHash(getClassname());
+ result *= fieldHash(getPackageName());
+ return result;
+ }
+
+ private int fieldHash(Object field){
+ if(field == null){
+ return SEED;
+ }
+ return field.hashCode();
+ }
+
+ /**
+ * Assumes all the fields are important for equals.
+ */
+ public boolean equals(Object artifact){
+ if(this == artifact){
+ return true;
+ } else if(!(artifact instanceof IndexedArtifact)){
+ return false;
+ } else {
+ IndexedArtifact other = (IndexedArtifact)artifact;
+ return fieldsEqual(this.getGroupId(), other.getGroupId()) &&
+ fieldsEqual(this.getArtifactId(), other.getArtifactId()) &&
+ fieldsEqual(this.getPackageName(), other.getPackageName()) &&
+ fieldsEqual(this.getPackaging(), other.getPackaging()) &&
+ fieldsEqual(this.getClassname(), other.getClassname());
+ }
+ }
+
+ private boolean fieldsEqual(Object field1, Object field2){
+ return field1 == null ? field2 == null : field1.equals(field2);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexedArtifactFile.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexedArtifactFile.java
new file mode 100644
index 00000000..46c60100
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/IndexedArtifactFile.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+import java.util.Date;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
+import org.apache.maven.model.Dependency;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+public class IndexedArtifactFile implements IAdaptable {
+
+ public final String repository;
+
+ public final String group;
+
+ public final String artifact;
+
+ public final String fname;
+
+ public final String version;
+
+ private ArtifactVersion artifactVersion;
+
+ public final String type;
+
+ public final String classifier;
+
+ public final long size;
+
+ public final Date date;
+
+ public final int sourcesExists;
+
+ public final int javadocExists;
+
+ public final String prefix;
+
+ public final List<String> goals;
+
+ public IndexedArtifactFile(String repository, String group, String artifact, String version, String type,
+ String classifier, String fname, long size, Date date, int sourcesExists, int javadocExists, String prefix,
+ List<String> goals) {
+ this.repository = repository;
+ this.group = group;
+ this.artifact = artifact;
+ this.version = version;
+ this.type = type;
+ this.classifier = classifier;
+ this.fname = fname;
+ this.size = size;
+ this.date = date == null ? null : new Date(date.getTime());
+ this.sourcesExists = sourcesExists;
+ this.javadocExists = javadocExists;
+ this.prefix = prefix;
+ this.goals = goals;
+ }
+
+ public ArtifactVersion getArtifactVersion() {
+ if (artifactVersion == null) {
+ artifactVersion = new DefaultArtifactVersion(version);
+ }
+ return artifactVersion;
+ }
+
+ public Dependency getDependency() {
+ Dependency dependency = new Dependency();
+ dependency.setArtifactId(artifact);
+ dependency.setGroupId(group);
+ dependency.setVersion(version);
+ dependency.setClassifier(classifier);
+ dependency.setType(type); // TODO: investigate difference between packaging and type
+ //http://docs.codehaus.org/display/MAVEN/Packaging+vs+Type+-+Derived+and+Attached+Artifacts
+ return dependency;
+ }
+
+ public ArtifactKey getArtifactKey() {
+ return new ArtifactKey(group, artifact, version, classifier);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if(adapter==ArtifactKey.class) {
+ return getArtifactKey();
+ }
+ return null;
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/MatchTyped.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/MatchTyped.java
new file mode 100644
index 00000000..e3c9363b
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/MatchTyped.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+/**
+ * MatchTyped is a interface that describes the wanted match type to be used.
+ *
+ * @author cstamas
+ */
+public interface MatchTyped {
+
+ public enum MatchType {
+ /** Exact match wanted */
+ EXACT,
+ /** Partial match wanted, like prefix, contains, etc. */
+ PARTIAL;
+ };
+
+ MatchType getMatchType();
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/MatchTypedStringSearchExpression.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/MatchTypedStringSearchExpression.java
new file mode 100644
index 00000000..23050079
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/MatchTypedStringSearchExpression.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+/**
+ * MatchTypedStringSearchExpression
+ *
+ * @author cstamas
+ */
+public class MatchTypedStringSearchExpression extends StringSearchExpression implements MatchTyped {
+
+ private final MatchType matchType;
+
+ public MatchTypedStringSearchExpression(final String expression, final MatchType matchType) {
+ super(expression);
+ this.matchType = matchType;
+ }
+
+ public MatchType getMatchType() {
+ return matchType;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/SearchExpression.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/SearchExpression.java
new file mode 100644
index 00000000..8b4592b2
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/SearchExpression.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+/**
+ * SearchExpression is a wrapper interface for expressions representable as plain strings to be used within searches.
+ *
+ * @author cstamas
+ */
+public interface SearchExpression {
+
+ /**
+ * Returns the expression value as plain java String.
+ *
+ * @return
+ */
+ String getStringValue();
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/SourcedSearchExpression.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/SourcedSearchExpression.java
new file mode 100644
index 00000000..f9932d03
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/SourcedSearchExpression.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+/**
+ * SourcedSearchExpression is a search expression usually "sourced" from some programmatic source, and we already know
+ * it is complete, exact value that we want to search for. Indexer will try to match exactly the provided string value,
+ * no more no less.
+ *
+ * @author cstamas
+ */
+public class SourcedSearchExpression extends MatchTypedStringSearchExpression {
+
+ public SourcedSearchExpression(String expression) {
+ super(expression, MatchType.EXACT);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/StringSearchExpression.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/StringSearchExpression.java
new file mode 100644
index 00000000..901d0c37
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/StringSearchExpression.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+/**
+ * StringSearchExpression is a SearchExpression that has String value.
+ *
+ * @author cstamas
+ */
+public class StringSearchExpression implements SearchExpression {
+
+ private final String expression;
+
+ public StringSearchExpression(String expression) {
+ assert expression != null && expression.trim().length() > 0 : "The expression cannot be empty!";
+ this.expression = expression;
+ }
+
+ public String getStringValue() {
+ return expression;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/UserInputSearchExpression.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/UserInputSearchExpression.java
new file mode 100644
index 00000000..dfa7ea7b
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/index/UserInputSearchExpression.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.index;
+
+/**
+ * UserInputSearchExpression is a search expression usually coming from user input (like some UI dialogue, element or
+ * CLI). It will be normalized and tokenized and then a search will happen against it. Search expressions of this type
+ * will always provide "broader" results, since it defaults to prefix searches.
+ *
+ * @author cstamas
+ */
+public class UserInputSearchExpression extends MatchTypedStringSearchExpression {
+
+ public UserInputSearchExpression(String expression) {
+ super(expression, MatchType.PARTIAL);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/ExtensionReader.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/ExtensionReader.java
new file mode 100644
index 00000000..c0c542e6
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/ExtensionReader.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IContributor;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.project.IMavenProjectChangedListener;
+
+
+/**
+ * Extension reader
+ *
+ * @author Eugene Kuleshov
+ */
+public class ExtensionReader {
+
+ public static final String EXTENSION_ARCHETYPES = IMavenConstants.PLUGIN_ID + ".archetypeCatalogs"; //$NON-NLS-1$
+
+ public static final String EXTENSION_PROJECT_CHANGED_EVENT_LISTENERS = IMavenConstants.PLUGIN_ID + ".mavenProjectChangedListeners"; //$NON-NLS-1$
+
+ private static final String ELEMENT_LOCAL_ARCHETYPE = "local"; //$NON-NLS-1$
+
+ private static final String ELEMENT_REMOTE_ARCHETYPE = "remote"; //$NON-NLS-1$
+
+ private static final String ATTR_NAME = "name"; //$NON-NLS-1$
+
+ private static final String ATTR_URL = "url"; //$NON-NLS-1$
+
+ private static final String ATTR_DESCRIPTION = "description"; //$NON-NLS-1$
+
+ private static final String ELEMENT_LISTENER = "listener"; //$NON-NLS-1$
+
+ public static List<ArchetypeCatalogFactory> readArchetypeExtensions() {
+ List<ArchetypeCatalogFactory> archetypeCatalogs = new ArrayList<ArchetypeCatalogFactory>();
+
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint archetypesExtensionPoint = registry.getExtensionPoint(EXTENSION_ARCHETYPES);
+ if(archetypesExtensionPoint != null) {
+ IExtension[] archetypesExtensions = archetypesExtensionPoint.getExtensions();
+ for(IExtension extension : archetypesExtensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ IContributor contributor = extension.getContributor();
+ for(IConfigurationElement element : elements) {
+ ArchetypeCatalogFactory factory = readArchetypeCatalogs(element, contributor);
+ // archetypeManager.addArchetypeCatalogFactory(factory);
+ archetypeCatalogs.add(factory);
+ }
+ }
+ }
+ return archetypeCatalogs;
+ }
+
+ private static ArchetypeCatalogFactory readArchetypeCatalogs(IConfigurationElement element, IContributor contributor) {
+ if(ELEMENT_LOCAL_ARCHETYPE.equals(element.getName())) {
+ String name = element.getAttribute(ATTR_NAME);
+ if(name != null) {
+ Bundle[] bundles = Platform.getBundles(contributor.getName(), null);
+ URL catalogUrl = null;
+ for(int i = 0; i < bundles.length; i++ ) {
+ Bundle bundle = bundles[i];
+ catalogUrl = bundle.getEntry(name);
+ if(catalogUrl != null) {
+ String description = element.getAttribute(ATTR_DESCRIPTION);
+ String url = catalogUrl.toString();
+ // XXX ARCHETYPE-161: RemoteCatalogArchetypeDataSource don't allow to download arbitrary urls
+ return new ArchetypeCatalogFactory.RemoteCatalogFactory(url.substring(0, url.lastIndexOf("/")), //$NON-NLS-1$
+ description, false);
+ }
+ }
+ MavenLogger.log("Unable to find Archetype catalog " + name + " in " + contributor.getName(), null);
+ }
+ } else if(ELEMENT_REMOTE_ARCHETYPE.equals(element.getName())) {
+ String url = element.getAttribute(ATTR_URL);
+ if(url != null) {
+ String description = element.getAttribute(ATTR_DESCRIPTION);
+ return new ArchetypeCatalogFactory.RemoteCatalogFactory(url, description, false);
+ }
+ }
+ return null;
+ }
+
+ public static List<IMavenProjectChangedListener> readProjectChangedEventListenerExtentions() {
+ ArrayList<IMavenProjectChangedListener> listeners = new ArrayList<IMavenProjectChangedListener>();
+
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint mappingsExtensionPoint = registry.getExtensionPoint(EXTENSION_PROJECT_CHANGED_EVENT_LISTENERS);
+ if(mappingsExtensionPoint != null) {
+ IExtension[] mappingsExtensions = mappingsExtensionPoint.getExtensions();
+ for(IExtension extension : mappingsExtensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for(IConfigurationElement element : elements) {
+ if(element.getName().equals(ELEMENT_LISTENER)) {
+ try {
+ listeners.add( (IMavenProjectChangedListener) element.createExecutableExtension("class") ); //$NON-NLS-1$
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+ }
+
+ return listeners;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Messages.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Messages.java
new file mode 100644
index 00000000..68a155d7
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Messages.java
@@ -0,0 +1,1024 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal;
+
+import org.eclipse.osgi.util.NLS;
+
+
+/**
+ * Messages
+ *
+ * @author mkleint
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.m2e.core.internal.messages"; //$NON-NLS-1$
+
+ public static String AbstractProjectConfigurator_error_missing_nature;
+
+ public static String AbstractTransferListenerAdapter_4;
+
+ public static String AbstractTransferListenerAdapter_byte;
+
+ public static String AbstractTransferListenerAdapter_cancelled;
+
+ public static String AbstractTransferListenerAdapter_kb;
+
+ public static String AbstractTransferListenerAdapter_mb;
+
+ public static String AbstractTransferListenerAdapter_subtask;
+
+ public static String AddDependencyAction_error_msg;
+
+ public static String AddDependencyAction_error_title;
+
+ public static String AddDependencyAction_searchDialog_title;
+
+ public static String AddDependencyDialog_artifactId_label;
+
+ public static String AddDependencyDialog_groupId_label;
+
+ public static String AddDependencyDialog_info_label;
+
+ public static String AddDependencyDialog_info_transitive;
+
+ public static String AddDependencyDialog_itemsSelected;
+ public static String AddDependencyDialog_itemSelected;
+
+ public static String AddDependencyDialog_multipleValuesSelected;
+
+ public static String AddDependencyDialog_results_label;
+
+ public static String AddDependencyDialog_scope_label;
+
+ public static String AddDependencyDialog_search_label;
+
+ public static String AddDependencyDialog_search_message;
+
+ public static String AddDependencyDialog_searchDone;
+
+ public static String AddDependencyDialog_searchError;
+
+ public static String AddDependencyDialog_searching;
+
+ public static String AddDependencyDialog_searchingFor;
+
+ public static String AddDependencyDialog_title;
+
+ public static String AddDependencyDialog_tooManyResults;
+
+ public static String AddDependencyDialog_transitive_dependency;
+
+ public static String AddDependencyDialog_version_label;
+
+ public static String AddPluginAction_searchDialog_title;
+
+ public static String ArchetypeCatalogFactory_default_local;
+
+ public static String ArchetypeCatalogFactory_error_missing_catalog;
+
+ public static String ArchetypeCatalogFactory_indexer_catalog;
+
+ public static String ArchetypeCatalogFactory_internal;
+
+ public static String ArchetypeCatalogFactory_local;
+
+ public static String ArchetypeCatalogFactory_remote;
+
+ public static String ArchetypeCatalogsWriter_error_parse;
+
+ public static String ArchetypeCatalogsWriter_error_write;
+
+ public static String AsyncFetcher_error_cancelled;
+
+ public static String AsyncFetcher_error_server;
+
+ public static String AsyncFetcher_task_fetching;
+
+ public static String AsyncFetcher_task_fetching2;
+
+ public static String ChangeNatureAction_job_changing;
+
+ public static String ChangeNatureAction_status_error;
+
+ public static String CustomArchetypeDialog_error_artid;
+
+ public static String CustomArchetypeDialog_error_grid;
+
+ public static String CustomArchetypeDialog_error_version;
+
+ public static String CustomArchetypeDialog_lblArchetypeartifactid;
+
+ public static String CustomArchetypeDialog_lblArchetypegroupId;
+
+ public static String CustomArchetypeDialog_lblArchetypeversion;
+
+ public static String CustomArchetypeDialog_lblRepo;
+
+ public static String CustomArchetypeDialog_message;
+
+ public static String CustomizableLifecycleMappingPropertyPage_message;
+
+ public static String CustomRepositoriesNode_name;
+
+ public static String DefaultMavenMenuCreator_action_ci;
+
+ public static String DefaultMavenMenuCreator_action_dependency;
+
+ public static String DefaultMavenMenuCreator_action_disable_management;
+
+ public static String DefaultMavenMenuCreator_action_disable_workspace;
+
+ public static String DefaultMavenMenuCreator_action_enable_dm;
+
+ public static String DefaultMavenMenuCreator_action_enable_workspace;
+
+ public static String DefaultMavenMenuCreator_action_issues;
+
+ public static String DefaultMavenMenuCreator_action_open_pom;
+
+ public static String DefaultMavenMenuCreator_action_plugin;
+
+ public static String DefaultMavenMenuCreator_action_project;
+
+ public static String DefaultMavenMenuCreator_action_project_page;
+
+ public static String DefaultMavenMenuCreator_action_scm;
+
+ public static String DefaultMavenMenuCreator_action_update_config;
+
+ public static String DefaultMavenMenuCreator_action_update_deps;
+
+ public static String DefaultMavenMenuCreator_action_update_snapshots;
+
+ public static String EclipseLogger_debug1;
+
+ public static String EclipseLogger_debug2;
+
+ public static String EclipseLogger_error1;
+
+ public static String EclipseLogger_error2;
+
+ public static String EclipseLogger_fatal1;
+
+ public static String EclipseLogger_fatal2;
+
+ public static String EclipseLogger_info1;
+
+ public static String EclipseLogger_info2;
+
+ public static String EclipseLogger_name;
+
+ public static String EclipseLogger_warn1;
+
+ public static String EclipseLogger_warn2;
+
+ public static String EditDependencyDialog_artifactId_label;
+
+ public static String EditDependencyDialog_classifier_label;
+
+ public static String EditDependencyDialog_groupId_label;
+
+ public static String EditDependencyDialog_optional_checkbox;
+
+ public static String EditDependencyDialog_scope_label;
+
+ public static String EditDependencyDialog_systemPath_label;
+
+ public static String EditDependencyDialog_title;
+
+ public static String EditDependencyDialog_type_label;
+
+ public static String EditDependencyDialog_version_label;
+
+ public static String EmptyLifecycleMappingPropertyPage_title;
+
+ public static String EnableNatureAction_job_enable;
+
+ public static String EnableNatureAction_wizard_shell;
+
+ public static String ExtensionReader_foundLifecycleMapping;
+
+ public static String GlobalRepositoriesNode_name;
+
+ public static String IndexedArtifactNode_no_pack;
+
+ public static String IndexUpdaterJob_title;
+
+ public static String LifecycleConfigurationMojoExecutionNotCovered;
+
+ public static String LifecycleMissing;
+
+ public static String LocalArchetypeCatalogDialog_btnBrowse;
+
+ public static String LocalArchetypeCatalogDialog_dialog_title;
+
+ public static String LocalArchetypeCatalogDialog_error_empty;
+
+ public static String LocalArchetypeCatalogDialog_error_exist;
+
+ public static String LocalArchetypeCatalogDialog_error_no_location;
+
+ public static String LocalArchetypeCatalogDialog_lblCatalog;
+
+ public static String LocalArchetypeCatalogDialog_lblDesc;
+
+ public static String LocalArchetypeCatalogDialog_message;
+
+ public static String LocalArchetypeCatalogDialog_title;
+
+ public static String LocalProjectScanner_task_scanning;
+
+ public static String LocalRepositoryNode_local;
+
+ public static String LocalRepositoryRootNode_name;
+
+ public static String M2EErrorDialog_column_error;
+
+ public static String M2EErrorDialog_column_name;
+
+ public static String MavenArchetypesPreferencePage_btnAddLocal;
+
+ public static String MavenArchetypesPreferencePage_btnAddRemote;
+
+ public static String MavenArchetypesPreferencePage_btnEdit;
+
+ public static String MavenArchetypesPreferencePage_btnRemove;
+
+ public static String MavenArchetypesPreferencePage_error;
+
+ public static String MavenArchetypesPreferencePage_link;
+
+ public static String MavenArchetypesPreferencePage_local;
+
+ public static String MavenArchetypesPreferencePage_packaged;
+
+ public static String MavenArchetypesPreferencePage_remote;
+
+ public static String MavenArchetypesPreferencePage_title;
+
+ public static String MavenCheckoutLocationPage_btnBrowse;
+
+ public static String MavenCheckoutLocationPage_btnCheckout;
+
+ public static String MavenCheckoutLocationPage_btnHead;
+
+ public static String MavenCheckoutLocationPage_btnRevSelect;
+
+ public static String MavenCheckoutLocationPage_description;
+
+ public static String MavenCheckoutLocationPage_error_empty;
+
+ public static String MavenCheckoutLocationPage_error_empty_url;
+
+ public static String MavenCheckoutLocationPage_error_scm_empty;
+
+ public static String MavenCheckoutLocationPage_error_scm_invalid;
+
+ public static String MavenCheckoutLocationPage_error_url_empty;
+
+ public static String MavenCheckoutLocationPage_lblRevision;
+
+ public static String MavenCheckoutLocationPage_lblurl;
+
+ public static String MavenCheckoutLocationPage_title;
+
+ public static String MavenCheckoutOperation_task_checking;
+
+ public static String MavenCheckoutOperation_task_scanning;
+
+ public static String MavenCheckoutWizard_location1;
+
+ public static String MavenCheckoutWizard_location2;
+
+ public static String MavenCheckoutWizard_title;
+
+ public static String MavenConsoleImpl_title;
+
+ public static String MavenConsolePageParticipant_any;
+
+ public static String MavenConsolePageParticipant_error;
+
+ public static String MavenConsoleRemoveAction_tooltip;
+
+ public static String MavenDebugOutputAction_0;
+
+ public static String MavenDependenciesWizardPage_lblArtifacts;
+
+ public static String MavenDependenciesWizardPage_searchDialog_title;
+
+ public static String MavenExternalRuntime_error_cannot_parse;
+
+ public static String MavenExternalRuntime_exc_unsupported;
+
+ public static String MavenExternalRuntime_unknown;
+
+ public static String MavenEmbeddedRuntime_unknown;
+
+ public static String MavenGoalSelectionDialog_btnQualified;
+
+ public static String MavenGoalSelectionDialog_error;
+
+ public static String MavenGoalSelectionDialog_lblSelect;
+
+ public static String MavenGoalSelectionDialog_message;
+
+ public static String MavenImpl_error_calc_build_plan;
+
+ public static String MavenImpl_error_create_repo;
+
+ public static String MavenImpl_error_init_maven;
+
+ public static String MavenImpl_error_lookup;
+
+ public static String MavenImpl_error_missing;
+
+ public static String MavenImpl_error_mojo;
+
+ public static String MavenImpl_error_no_exec_req;
+
+ public static String MavenImpl_error_param;
+
+ public static String MavenImpl_error_read_config;
+
+ public static String MavenImpl_error_read_lastUpdated;
+
+ public static String MavenImpl_error_read_pom;
+
+ public static String MavenImpl_error_read_project;
+
+ public static String MavenImpl_error_read_settings;
+
+ public static String MavenImpl_error_read_settings2;
+
+ public static String MavenImpl_error_resolve;
+
+ public static String MavenImpl_error_sort;
+
+ public static String MavenImpl_error_write_lastUpdated;
+
+ public static String MavenImpl_error_write_pom;
+
+ public static String MavenImpl_error_write_settings;
+
+ public static String MavenImportWizard_job;
+
+ public static String MavenImportWizard_title;
+
+ public static String MavenImportWizardPage_desc;
+
+ public static String MavenImportWizardPage_inherited;
+
+ public static String MavenImportWizardPage_title;
+
+ public static String MavenInstallationsPreferencePage_btnAdd;
+
+ public static String MavenInstallationsPreferencePage_btnEdit;
+
+ public static String MavenInstallationsPreferencePage_btnGlobalBrowse;
+
+ public static String MavenInstallationsPreferencePage_btnRemove;
+
+ public static String MavenInstallationsPreferencePage_dialog_install_message;
+
+ public static String MavenInstallationsPreferencePage_dialog_install_title;
+
+ public static String MavenInstallationsPreferencePage_dialog_message;
+
+ public static String MavenInstallationsPreferencePage_dialog_title;
+
+ public static String MavenInstallationsPreferencePage_error_global_missing;
+
+ public static String MavenInstallationsPreferencePage_error_global_parse;
+
+ public static String MavenInstallationsPreferencePage_error_message;
+
+ public static String MavenInstallationsPreferencePage_error_title;
+
+ public static String MavenInstallationsPreferencePage_error2_message;
+
+ public static String MavenInstallationsPreferencePage_error3_message;
+
+ public static String MavenInstallationsPreferencePage_error4_message;
+
+ public static String MavenInstallationsPreferencePage_job_updating;
+
+ public static String MavenInstallationsPreferencePage_lblNote1;
+
+ public static String MavenInstallationsPreferencePage_lblNote2;
+
+ public static String MavenInstallationsPreferencePage_link;
+
+ public static String MavenInstallationsPreferencePage_link_global;
+
+ public static String MavenInstallationsPreferencePage_link_open;
+
+ public static String MavenInstallationsPreferencePage_settings;
+
+ public static String MavenInstallationsPreferencePage_settings_install;
+
+ public static String MavenInstallationsPreferencePage_title;
+
+ public static String MavenInstallFileArtifactWizardPage_btnChecksum;
+
+ public static String MavenInstallFileArtifactWizardPage_btnFilename;
+
+ public static String MavenInstallFileArtifactWizardPage_btnGenerate;
+
+ public static String MavenInstallFileArtifactWizardPage_btnPom;
+
+ public static String MavenInstallFileArtifactWizardPage_desc;
+
+ public static String MavenInstallFileArtifactWizardPage_error_artifactid;
+
+ public static String MavenInstallFileArtifactWizardPage_error_groupid;
+
+ public static String MavenInstallFileArtifactWizardPage_error_missing;
+
+ public static String MavenInstallFileArtifactWizardPage_error_missingpom;
+
+ public static String MavenInstallFileArtifactWizardPage_error_no_name;
+
+ public static String MavenInstallFileArtifactWizardPage_error_packaging;
+
+ public static String MavenInstallFileArtifactWizardPage_error_version;
+
+ public static String MavenInstallFileArtifactWizardPage_file_title;
+
+ public static String MavenInstallFileArtifactWizardPage_lblArtifact;
+
+ public static String MavenInstallFileArtifactWizardPage_lblClassifier;
+
+ public static String MavenInstallFileArtifactWizardPage_lblFileName;
+
+ public static String MavenInstallFileArtifactWizardPage_lblgroupid;
+
+ public static String MavenInstallFileArtifactWizardPage_lblPackaging;
+
+ public static String MavenInstallFileArtifactWizardPage_lblPom;
+
+ public static String MavenInstallFileArtifactWizardPage_lblVersion;
+
+ public static String MavenInstallFileArtifactWizardPage_message;
+
+ public static String MavenInstallFileArtifactWizardPage_title;
+
+ public static String MavenInstallFileWizard_error;
+
+ public static String MavenInstallFileWizard_job;
+
+ public static String MavenInstallFileWizard_title;
+
+ public static String MavenMarkerManager_duplicate_groupid;
+
+ public static String MavenMarkerManager_duplicate_version;
+
+ public static String MavenMarkerManager_error_artifact;
+
+ public static String MavenMarkerManager_error_missing;
+
+ public static String MavenMarkerManager_error_noschema;
+
+ public static String MavenMarkerManager_error_offline;
+
+ public static String MavenMarkerManager_managed_title;
+
+ public static String MavenMarkerManager_metadata_resolution;
+
+ public static String MavenMaterializePomWizard_btnCheckout;
+
+ public static String MavenMaterializePomWizard_btnDev;
+
+ public static String MavenMaterializePomWizard_dialog_message;
+
+ public static String MavenMaterializePomWizard_dialog_title;
+
+ public static String MavenMaterializePomWizard_location_message;
+
+ public static String MavenMaterializePomWizard_location_title;
+
+ public static String MavenMaterializePomWizard_title;
+
+ public static String MavenModelManager_error_cannot_load;
+
+ public static String MavenModelManager_error_create;
+
+ public static String MavenModelManager_error_pom_exists;
+
+ public static String MavenModelManager_error_read;
+
+ public static String MavenModelManager_monitor_building;
+
+ public static String MavenModelManager_monitor_reading;
+
+ public static String MavenModuleWizardParentPage_error;
+
+ public static String MavenPlugin_error_jre_message;
+
+ public static String MavenPlugin_error_jre_title;
+
+ public static String MavenPlugin_error_warn_again;
+
+ public static String MavenPomSelectionComponent_btnJavadoc;
+
+ public static String MavenPomSelectionComponent_btnSource;
+
+ public static String MavenPomSelectionComponent_btnTests;
+
+ public static String MavenPomSelectionComponent_detail1;
+
+ public static String MavenPomSelectionComponent_details2;
+
+ public static String MavenPomSelectionComponent_error;
+
+ public static String MavenPomSelectionComponent_lblResults;
+
+ public static String MavenPomSelectionComponent_managed_decoration;
+
+ public static String MavenPomSelectionComponent_nosel;
+
+ public static String MavenPomSelectionComponent_results;
+
+ public static String MavenPomSelectionComponent_search_title;
+
+ public static String MavenPomSelectionComponent_searching;
+
+ public static String MavenPomSelectionComponent_searchJob;
+
+ public static String MavenPomSelectionComponent_selected;
+
+ public static String MavenPomSelectionComponent_toomany;
+
+ public static String MavenPomSelectionComponent_tooshort;
+
+ public static String MavenPomWizard_error_exists;
+
+ public static String MavenPomWizard_error_title;
+
+ public static String MavenPomWizard_status_not_exists;
+
+ public static String MavenPomWizard_task;
+
+ public static String MavenPomWizard_title;
+
+ public static String MavenPomWizardPage_btnBrowse;
+
+ public static String MavenPomWizardPage_desc;
+
+ public static String MavenPomWizardPage_dialog_title;
+
+ public static String MavenPomWizardPage_error_artid;
+
+ public static String MavenPomWizardPage_error_folder;
+
+ public static String MavenPomWizardPage_error_folder_write;
+
+ public static String MavenPomWizardPage_error_folder2;
+
+ public static String MavenPomWizardPage_error_grid;
+
+ public static String MavenPomWizardPage_error_pack;
+
+ public static String MavenPomWizardPage_error_version;
+
+ public static String MavenPomWizardPage_lblProject;
+
+ public static String MavenPomWizardPage_title;
+
+ public static String MavenPreferencePage_download;
+
+ public static String MavenPreferencePage_hide;
+
+ public static String MavenPreferencePage_select;
+
+ public static String MavenPreferencePage_select2;
+
+ public static String MavenPreferencePage_update;
+
+ public static String MavenProjectCheckoutJob_confirm_message;
+
+ public static String MavenProjectCheckoutJob_confirm_title;
+
+ public static String MavenProjectCheckoutJob_confirm2_message;
+
+ public static String MavenProjectCheckoutJob_confirm2_title;
+
+ public static String MavenProjectCheckoutJob_job;
+
+ public static String MavenProjectCheckoutJob_title;
+
+ public static String MavenProjectFacade_error;
+
+ public static String MavenProjectLifecycleMappingPage_error_no_page;
+
+ public static String MavenProjectLifecycleMappingPage_error_no_strategy;
+
+ public static String MavenProjectLifecycleMappingPage_error_page_error;
+
+ public static String MavenProjectPomScanner_23;
+
+ public static String MavenProjectPomScanner_task_resolving;
+
+ public static String MavenProjectPreferencePage_btnResolve;
+
+ public static String MavenProjectPreferencePage_dialog_message;
+
+ public static String MavenProjectPreferencePage_dialog_title;
+
+ public static String MavenProjectPreferencePage_job;
+
+ public static String MavenProjectPreferencePage_lblProfiles;
+
+ public static String MavenProjectPreferencePage_title;
+
+ public static String MavenProjectWizardArchetypePage_add_title;
+
+ public static String MavenProjectWizardArchetypePage_all;
+
+ public static String MavenProjectWizardArchetypePage_btnAdd;
+
+ public static String MavenProjectWizardArchetypePage_btnConfigure;
+
+ public static String MavenProjectWizardArchetypePage_btnLast;
+
+ public static String MavenProjectWizardArchetypePage_btnSnapshots;
+
+ public static String MavenProjectWizardArchetypePage_error_no;
+
+ public static String MavenProjectWizardArchetypePage_error_read;
+
+ public static String MavenProjectWizardArchetypePage_error_resolve;
+
+ public static String MavenProjectWizardArchetypePage_error_resolve2;
+
+ public static String MavenProjectWizardArchetypePage_lblCatalog;
+
+ public static String MavenProjectWizardArchetypePage_lblFilter;
+
+ public static String MavenProjectWizardArchetypePage_task_downloading;
+
+ public static String MavenProjectWizardArchetypePage_task_indexing;
+
+ public static String MavenProjectWizardArchetypePage_task_reading;
+
+ public static String MavenProjectWizardArchetypePage_task_resolving;
+
+ public static String MavenProjectWizardArchetypePage_task_resolving2;
+
+ public static String MavenProjectWizardArchetypeParametersPage_btnAdd;
+
+ public static String MavenProjectWizardArchetypeParametersPage_btnRemove;
+
+ public static String MavenProjectWizardArchetypeParametersPage_columnName;
+
+ public static String MavenProjectWizardArchetypeParametersPage_columnValue;
+
+ public static String MavenProjectWizardArchetypeParametersPage_error_download;
+
+ public static String MavenProjectWizardArchetypeParametersPage_error_package;
+
+ public static String MavenProjectWizardArchetypeParametersPage_lblProps;
+
+ public static String MavenProjectWizardArchetypeParametersPage_task;
+
+ public static String MavenProjectWizardArtifactPage_searchDialog_title;
+
+ public static String MavenProjectWizardLocationPage_btnLocation;
+
+ public static String MavenProjectWizardLocationPage_btnUserDefault;
+
+ public static String MavenProjectWizardLocationPage_dialog_location;
+
+ public static String MavenProjectWizardLocationPage_lblLocation;
+
+ public static String MavenRepositorySearchDialog_7;
+
+ public static String MavenRepositorySearchDialog_lblScope;
+
+ public static String MavenRepositoryView_action_copy;
+
+ public static String MavenRepositoryView_action_copy_tooltip;
+
+ public static String MavenRepositoryView_action_disable_tooltip;
+
+ public static String MavenRepositoryView_action_enable_tooltip;
+
+ public static String MavenRepositoryView_action_enableFull_tooltip;
+
+ public static String MavenRepositoryView_action_materialize;
+
+ public static String MavenRepositoryView_action_open;
+
+ public static String MavenRepositoryView_action_open_tooltip;
+
+ public static String MavenRepositoryView_action_rebuild;
+
+ public static String MavenRepositoryView_action_rebuild_tooltip;
+
+ public static String MavenRepositoryView_action_reload;
+
+ public static String MavenRepositoryView_action_update;
+
+ public static String MavenRepositoryView_btnCollapse;
+
+ public static String MavenRepositoryView_btnCollapse_tooltip;
+
+ public static String MavenRepositoryView_btnUpdate_tooltip;
+
+ public static String MavenRepositoryView_details_disabled;
+
+ public static String MavenRepositoryView_disable_details;
+
+ public static String MavenRepositoryView_enable_full;
+
+ public static String MavenRepositoryView_enable_minimum;
+
+ public static String MavenRepositoryView_enabled_full;
+
+ public static String MavenRepositoryView_error_message;
+
+ public static String MavenRepositoryView_error_title;
+
+ public static String MavenRepositoryView_job_reloading;
+
+ public static String MavenRepositoryView_minimum_enabled;
+
+ public static String MavenRepositoryView_rebuild_many;
+
+ public static String MavenRepositoryView_rebuild_msg;
+
+ public static String MavenRepositoryView_rebuild_msg2;
+
+ public static String MavenRepositoryView_rebuild_one;
+
+ public static String MavenRepositoryView_rebuild_title;
+
+ public static String MavenRepositoryView_rebuild_title2;
+
+ public static String MavenRepositoryView_reload_msg;
+
+ public static String MavenRepositoryView_reload_title;
+
+ public static String MavenRepositoryView_update_more;
+
+ public static String MavenRepositoryView_update_one;
+
+ public static String MavenSearchPage_btnBrowse;
+
+ public static String MavenSearchPage_btnSelect;
+
+ public static String MavenSearchPage_btnUnselect;
+
+ public static String MavenSearchPage_lblArtifactid;
+
+ public static String MavenSearchPage_lblClass;
+
+ public static String MavenSearchPage_lblGroupid;
+
+ public static String MavenSearchPage_lblPackaging;
+
+ public static String MavenSearchPage_lblRepos;
+
+ public static String MavenSearchPage_lblSha;
+
+ public static String MavenSearchPage_lblVersion;
+
+ public static String MavenSearchPage_separator;
+
+ public static String MavenSettingsPreferencePage_btnBrowse;
+
+ public static String MavenSettingsPreferencePage_btnUpdate;
+
+ public static String MavenSettingsPreferencePage_error_missing;
+
+ public static String MavenSettingsPreferencePage_error_parse;
+
+ public static String MavenSettingsPreferencePage_job_indexing;
+
+ public static String MavenSettingsPreferencePage_job_updating;
+
+ public static String MavenSettingsPreferencePage_lblLocal;
+
+ public static String MavenSettingsPreferencePage_link_tooltip;
+
+ public static String MavenSettingsPreferencePage_link1;
+
+ public static String MavenSettingsPreferencePage_link2;
+
+ public static String MavenSettingsPreferencePage_task_updating;
+
+ public static String MavenSettingsPreferencePage_title;
+
+ public static String MissingLifecycleMapping_name;
+ public static String MissingLifecycleMappingPropertyPage_error;
+
+ public static String MissingLifecycleMappingPropertyPage_title;
+
+ public static String NexusIndexManager_78;
+
+ public static String NexusIndexManager_error_add_repo;
+
+ public static String NexusIndexManager_error_read_index;
+
+ public static String NexusIndexManager_error_reindexing;
+
+ public static String NexusIndexManager_error_root_grp;
+
+ public static String NexusIndexManager_error_search;
+
+ public static String NexusIndexManager_error_unexpected;
+
+ public static String NexusIndexManager_error_write_index;
+
+ public static String NexusIndexManager_inherited;
+
+ public static String NexusIndexManager_task_updating;
+
+ public static String OpenPomAction_33;
+
+ public static String OpenPomAction_error_download;
+
+ public static String OpenPomAction_error_download_source;
+
+ public static String OpenPomAction_error_open_editor;
+
+ public static String OpenPomAction_error_open_pom;
+
+ public static String OpenPomAction_job_opening;
+
+ public static String OpenPomAction_open_error_message;
+
+ public static String OpenPomAction_open_error_title;
+
+ public static String OpenPomAction_open_title;
+
+ public static String OpenPomAction_title_pom;
+
+ public static String OpenUrlAction_browser_title;
+
+ public static String OpenUrlAction_error_no_ci;
+
+ public static String OpenUrlAction_error_no_issues;
+
+ public static String OpenUrlAction_error_no_scm;
+
+ public static String OpenUrlAction_error_no_url;
+
+ public static String OpenUrlAction_error_open;
+
+ public static String OpenUrlAction_job_browser;
+
+ public static String OpenUrlAction_open_url_message;
+
+ public static String OpenUrlAction_open_url_title;
+
+ public static String PomFileContentDescriber_error;
+
+ public static String ProjectConfigurationManager_0;
+
+ public static String ProjectConfigurationManager_error_failed;
+
+ public static String ProjectConfigurationManager_error_rename;
+
+ public static String ProjectConfigurationManager_error_resolve;
+
+ public static String ProjectConfigurationManager_error_resolve2;
+
+ public static String ProjectConfigurationManager_error_targetDir;
+
+ public static String ProjectConfigurationManager_error_unable_archetype;
+
+ public static String ProjectConfigurationManager_task_configuring;
+
+ public static String ProjectConfigurationManager_task_creating;
+
+ public static String ProjectConfigurationManager_task_creating_folders;
+
+ public static String ProjectConfigurationManager_task_creating_pom;
+
+ public static String ProjectConfigurationManager_task_creating_project;
+
+ public static String ProjectConfigurationManager_task_creating_project1;
+
+ public static String ProjectConfigurationManager_task_creating_workspace;
+
+ public static String ProjectConfigurationManager_task_disable_nature;
+
+ public static String ProjectConfigurationManager_task_enable_nature;
+
+ public static String ProjectConfigurationManager_task_executing_archetype;
+
+ public static String ProjectConfigurationManager_task_importing;
+
+ public static String ProjectConfigurationManager_task_importing2;
+
+ public static String ProjectConfigurationManager_task_refreshing;
+
+ public static String ProjectConfigurationManager_task_updating;
+
+ public static String ProjectConfiguratorsTable_column_id;
+
+ public static String ProjectConfiguratorsTable_column_name;
+
+ public static String ProjectConfiguratorsTableContentProvider_no_configs;
+
+ public static String ProjectRegistryManager_task_project;
+
+ public static String ProjectRegistryManager_task_refreshing;
+
+ public static String ProjectRegistryRefreshJob_task_refreshing;
+
+ public static String ProjectRegistryRefreshJob_title;
+
+ public static String ProjectRepositoriesNode_name;
+
+ public static String ProjectsImportPage_btnDeselect;
+
+ public static String ProjectsImportPage_btnRefresh;
+
+ public static String ProjectsImportPage_btnSelect;
+
+ public static String ProjectsImportPage_desc;
+
+ public static String ProjectsImportPage_dialog_title;
+
+ public static String ProjectsImportPage_error_creation;
+
+ public static String ProjectsImportPage_lstProjects;
+
+ public static String ProjectsImportPage_message;
+
+ public static String ProjectsImportPage_overwrite;
+
+ public static String ProjectsImportPage_overwrite2;
+
+ public static String ProjectsImportPage_task_checking;
+
+ public static String ProjectsImportPage_task_creating;
+
+ public static String ProjectsImportPage_task_processing;
+
+ public static String ProjectsImportPage_task_search;
+
+ public static String ProjectsImportPage_title;
+
+ public static String ProjectsImportWizard_title;
+
+ public static String RemoteArchetypeCatalogDialog_btnVerify;
+
+ public static String RemoteArchetypeCatalogDialog_error_empty;
+
+ public static String RemoteArchetypeCatalogDialog_error_read;
+
+ public static String RemoteArchetypeCatalogDialog_error_required;
+
+ public static String RemoteArchetypeCatalogDialog_job_download;
+
+ public static String RemoteArchetypeCatalogDialog_lblCatalog;
+
+ public static String RemoteArchetypeCatalogDialog_lblDesc;
+
+ public static String RemoteArchetypeCatalogDialog_message;
+
+ public static String RemoteArchetypeCatalogDialog_message_found;
+
+ public static String RemoteArchetypeCatalogDialog_title;
+
+ public static String RepositoryNode_updating;
+
+ public static String RepositoryRegistryUpdateJob_title;
+
+ public static String ScmUrl_error;
+
+ public static String SelectionUtil_error_cannot_read;
+ public static String UpdateSourcesAction_error_cannot_update;
+
+ public static String UpdateSourcesAction_error_message;
+
+ public static String UpdateSourcesAction_error_title;
+
+ public static String UpdateSourcesAction_job_update_conf;
+
+ public static String WorkingSetGroup_btnAddSet;
+
+ public static String WorkingSetGroup_btnMore;
+
+ public static String WorkingSetGroup_lblSet;
+
+ public static String WorkspaceRepositoryNode_name;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/actions/DefaultMavenMenuCreator.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/actions/DefaultMavenMenuCreator.java
new file mode 100644
index 00000000..40221b63
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/actions/DefaultMavenMenuCreator.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.actions;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.actions.AbstractMavenMenuCreator;
+import org.eclipse.m2e.core.actions.AddDependencyAction;
+import org.eclipse.m2e.core.actions.AddPluginAction;
+import org.eclipse.m2e.core.actions.ChangeNatureAction;
+import org.eclipse.m2e.core.actions.DisableNatureAction;
+import org.eclipse.m2e.core.actions.EnableNatureAction;
+import org.eclipse.m2e.core.actions.ModuleProjectWizardAction;
+import org.eclipse.m2e.core.actions.OpenPomAction;
+import org.eclipse.m2e.core.actions.OpenUrlAction;
+import org.eclipse.m2e.core.actions.RefreshMavenModelsAction;
+import org.eclipse.m2e.core.actions.SelectionUtil;
+import org.eclipse.m2e.core.actions.UpdateConfigurationAction;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.project.ResolverConfiguration;
+
+
+/**
+ * Default Maven menu creator
+ *
+ * @author Eugene Kuleshov
+ */
+public class DefaultMavenMenuCreator extends AbstractMavenMenuCreator {
+
+ public void createMenu(IMenuManager mgr) {
+ int selectionType = SelectionUtil.getSelectionType(selection);
+ if(selectionType == SelectionUtil.UNSUPPORTED) {
+ return;
+ }
+
+ if(selection.size() == 1 && selectionType == SelectionUtil.POM_FILE) {
+ mgr.appendToGroup(NEW, getAction(new AddDependencyAction(), //
+ AddDependencyAction.ID, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_dependency));
+ mgr.appendToGroup(NEW, getAction(new AddPluginAction(), AddPluginAction.ID, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_plugin));
+ mgr.appendToGroup(NEW, getAction(new ModuleProjectWizardAction(), //
+ ModuleProjectWizardAction.ID, Messages.getString("action.moduleProjectWizardAction"))); //$NON-NLS-1$
+
+ mgr.prependToGroup(OPEN, new Separator());
+ mgr.appendToGroup(OPEN, getAction(new OpenUrlAction(OpenUrlAction.ID_PROJECT), //
+ OpenUrlAction.ID_PROJECT, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_project_page));
+ mgr.appendToGroup(OPEN, getAction(new OpenUrlAction(OpenUrlAction.ID_ISSUES), //
+ OpenUrlAction.ID_ISSUES, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_issues));
+ mgr.appendToGroup(OPEN, getAction(new OpenUrlAction(OpenUrlAction.ID_SCM), //
+ OpenUrlAction.ID_SCM, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_scm));
+ mgr.appendToGroup(OPEN, getAction(new OpenUrlAction(OpenUrlAction.ID_CI), //
+ OpenUrlAction.ID_CI, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_ci));
+ }
+
+ if(selectionType == SelectionUtil.PROJECT_WITHOUT_NATURE) {
+ mgr.appendToGroup(NATURE, getAction(new EnableNatureAction(), //
+ EnableNatureAction.ID, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_enable_dm));
+ }
+
+ if(selectionType == SelectionUtil.PROJECT_WITH_NATURE) {
+ if(selection.size() == 1) {
+ mgr.appendToGroup(NEW, getAction(new AddDependencyAction(), AddDependencyAction.ID, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_dependency));
+ mgr.appendToGroup(NEW, getAction(new AddPluginAction(), AddPluginAction.ID, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_plugin));
+ mgr.appendToGroup(NEW, getAction(new ModuleProjectWizardAction(), //
+ ModuleProjectWizardAction.ID, Messages.getString("action.moduleProjectWizardAction"))); //$NON-NLS-1$
+ mgr.prependToGroup(UPDATE, new Separator());
+ }
+
+
+ mgr.appendToGroup(UPDATE, getAction(new RefreshMavenModelsAction(), RefreshMavenModelsAction.ID,
+ org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_update_deps, "icons/update_dependencies.gif")); //$NON-NLS-2$
+ mgr.appendToGroup(UPDATE, getAction(new RefreshMavenModelsAction(true), RefreshMavenModelsAction.ID_SNAPSHOTS,
+ org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_update_snapshots));
+ mgr.appendToGroup(UPDATE, getAction(new UpdateConfigurationAction(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()), //
+ UpdateConfigurationAction.ID, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_update_config, "icons/update_source_folders.gif")); //$NON-NLS-2$
+
+ mgr.prependToGroup(OPEN, new Separator());
+ mgr.appendToGroup(OPEN, getAction(new OpenPomAction(), OpenPomAction.ID, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_open_pom));
+ mgr.appendToGroup(OPEN, getAction(new OpenUrlAction(OpenUrlAction.ID_PROJECT), //
+ OpenUrlAction.ID_PROJECT, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_project));
+ mgr.appendToGroup(OPEN, getAction(new OpenUrlAction(OpenUrlAction.ID_ISSUES), OpenUrlAction.ID_ISSUES,
+ org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_issues));
+ mgr.appendToGroup(OPEN, getAction(new OpenUrlAction(OpenUrlAction.ID_SCM), OpenUrlAction.ID_SCM,
+ org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_scm));
+ mgr.appendToGroup(OPEN, getAction(new OpenUrlAction(OpenUrlAction.ID_CI), OpenUrlAction.ID_CI,
+ org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_ci));
+
+ boolean enableWorkspaceResolution = true;
+ if(selection.size() == 1) {
+ IProject project = SelectionUtil.getType(selection.getFirstElement(), IProject.class);
+ if(project != null) {
+ MavenProjectManager projectManager = MavenPlugin.getDefault().getMavenProjectManager();
+ IMavenProjectFacade projectFacade = projectManager.create(project, new NullProgressMonitor());
+ if(projectFacade != null) {
+ ResolverConfiguration configuration = projectFacade.getResolverConfiguration();
+ enableWorkspaceResolution = !configuration.shouldResolveWorkspaceProjects();
+ }
+ }
+ }
+
+ mgr.prependToGroup(NATURE, new Separator());
+ if(enableWorkspaceResolution) {
+ mgr.appendToGroup(NATURE, getAction(new ChangeNatureAction(ChangeNatureAction.ENABLE_WORKSPACE),
+ ChangeNatureAction.ID_ENABLE_WORKSPACE, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_enable_workspace));
+ } else {
+ mgr.appendToGroup(NATURE, getAction(new ChangeNatureAction(ChangeNatureAction.DISABLE_WORKSPACE),
+ ChangeNatureAction.ID_DISABLE_WORKSPACE, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_disable_workspace));
+ }
+
+ mgr.appendToGroup(NATURE, getAction(new DisableNatureAction(), //
+ DisableNatureAction.ID, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_disable_management));
+ }
+
+ if(selectionType == SelectionUtil.WORKING_SET) {
+ mgr.appendToGroup(UPDATE, getAction(new RefreshMavenModelsAction(), RefreshMavenModelsAction.ID,
+ org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_update_deps, "icons/update_dependencies.gif")); //$NON-NLS-2$
+ mgr.appendToGroup(UPDATE, getAction(new RefreshMavenModelsAction(true), RefreshMavenModelsAction.ID_SNAPSHOTS,
+ org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_update_snapshots));
+ mgr.appendToGroup(UPDATE, getAction(new UpdateConfigurationAction(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()), //
+ UpdateConfigurationAction.ID, org.eclipse.m2e.core.internal.Messages.DefaultMavenMenuCreator_action_update_config, "icons/update_source_folders.gif")); //$NON-NLS-2$
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/InternalBuildParticipant.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/InternalBuildParticipant.java
new file mode 100644
index 00000000..7a78ff52
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/InternalBuildParticipant.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.builder;
+
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.execution.MavenSession;
+
+import org.sonatype.plexus.build.incremental.BuildContext;
+
+import org.eclipse.m2e.core.builder.AbstractEclipseBuildContext;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+public abstract class InternalBuildParticipant {
+
+ private IMavenProjectFacade facade;
+ private MavenBuilder.GetDeltaCallback getDeltaCallback;
+// private BuildContext buildContext;
+ private MavenSession session;
+ private AbstractEclipseBuildContext buildContext;
+
+ protected IMavenProjectFacade getMavenProjectFacade() {
+ return facade;
+ }
+
+ void setMavenProjectFacade(IMavenProjectFacade facade) {
+ this.facade = facade;
+ }
+
+ protected IResourceDelta getDelta(IProject project) {
+ return getDeltaCallback.getDelta(project);
+ }
+
+ void setGetDeltaCallback(MavenBuilder.GetDeltaCallback getDeltaCallback) {
+ this.getDeltaCallback = getDeltaCallback;
+ }
+
+ protected MavenSession getSession() {
+ return session;
+ }
+
+ void setSession(MavenSession session) {
+ this.session = session;
+ }
+
+ public abstract Set<IProject> build(int kind, IProgressMonitor monitor) throws Exception;
+
+ @SuppressWarnings("unused")
+ public void clean(IProgressMonitor monitor) throws CoreException {
+ // default implementation does nothing
+ }
+
+ public abstract boolean callOnEmptyDelta();
+
+ void setBuildContext(AbstractEclipseBuildContext buildContext) {
+ this.buildContext = buildContext;
+ }
+
+ protected BuildContext getBuildContext() {
+ return buildContext;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilder.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilder.java
new file mode 100644
index 00000000..0e13bd10
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenBuilder.java
@@ -0,0 +1,302 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.builder;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.QualifiedName;
+
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+
+import org.sonatype.plexus.build.incremental.ThreadBuildContext;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.builder.AbstractEclipseBuildContext;
+import org.eclipse.m2e.core.builder.EclipseBuildContext;
+import org.eclipse.m2e.core.builder.EclipseIncrementalBuildContext;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.project.IMavenMarkerManager;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.IProjectConfigurationManager;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.project.MavenUpdateRequest;
+import org.eclipse.m2e.core.project.configurator.AbstractBuildParticipant;
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+import org.eclipse.m2e.core.util.M2EUtils;
+
+
+public class MavenBuilder extends IncrementalProjectBuilder {
+
+ public static boolean DEBUG = MavenPlugin.getDefault().isDebugging()
+ & Boolean.parseBoolean(Platform.getDebugOption(IMavenConstants.PLUGIN_ID + "/debug/builder")); //$NON-NLS-1$
+
+ public static QualifiedName BUILD_CONTEXT_KEY = new QualifiedName(IMavenConstants.PLUGIN_ID, "BuildContext"); //$NON-NLS-1$
+
+ static interface GetDeltaCallback {
+ public IResourceDelta getDelta(IProject project);
+ }
+
+ private GetDeltaCallback getDeltaCallback = new GetDeltaCallback() {
+ public IResourceDelta getDelta(IProject project) {
+ return MavenBuilder.this.getDelta(project);
+ }
+ };
+
+ /*
+ * @see org.eclipse.core.internal.events.InternalBuilder#build(int,
+ * java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @SuppressWarnings("unchecked")
+ protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ MavenConsole console = plugin.getConsole();
+ MavenProjectManager projectManager = plugin.getMavenProjectManager();
+ IProjectConfigurationManager configurationManager = plugin.getProjectConfigurationManager();
+ IMavenConfiguration mavenConfiguration = MavenPlugin.getDefault().getMavenConfiguration();
+ IMavenMarkerManager markerManager = plugin.getMavenMarkerManager();
+
+ IProject project = getProject();
+ markerManager.deleteMarkers(project, IMavenConstants.MARKER_BUILD_ID);
+
+ if(project.hasNature(IMavenConstants.NATURE_ID)) {
+ IFile pomResource = project.getFile(IMavenConstants.POM_FILE_NAME);
+ if(pomResource == null) {
+ console.logError("Project " + project.getName() + " does not have pom.xml");
+ return null;
+ }
+
+ IMavenProjectFacade projectFacade = projectManager.create(getProject(), monitor);
+ if(projectFacade == null) {
+ // XXX is this really possible? should we warn the user?
+ return null;
+ }
+
+ if (projectFacade.isStale()) {
+ MavenUpdateRequest updateRequest = new MavenUpdateRequest(project, mavenConfiguration.isOffline() /*offline*/, false /*updateSnapshots*/);
+ projectManager.refresh(updateRequest, monitor);
+ IMavenProjectFacade facade = projectManager.create(project, monitor);
+ if(facade == null){
+ // error marker should have been created
+ return null;
+ }
+ }
+
+ IResourceDelta delta = getDelta(project);
+ AbstractEclipseBuildContext buildContext;
+ Map<String, Object> contextState = (Map<String, Object>) project.getSessionProperty(BUILD_CONTEXT_KEY);
+ if(contextState != null && (INCREMENTAL_BUILD == kind || AUTO_BUILD == kind)) {
+ buildContext = new EclipseIncrementalBuildContext(delta, contextState);
+ } else {
+ // must be full build
+ contextState = new HashMap<String, Object>();
+ project.setSessionProperty(BUILD_CONTEXT_KEY, contextState);
+ buildContext = new EclipseBuildContext(project, contextState);
+ }
+
+ Set<IProject> dependencies = new HashSet<IProject>();
+
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+ MavenExecutionRequest request = projectManager.createExecutionRequest(pomResource, projectFacade.getResolverConfiguration(), monitor);
+
+ MavenProject mavenProject = null;
+ try{
+ mavenProject = projectFacade.getMavenProject(monitor);
+ } catch(CoreException ce){
+ //unable to read the project facade
+ addErrorMarker(ce);
+ monitor.done();
+ return null;
+ }
+ MavenSession session = maven.createSession(request, mavenProject);
+ ILifecycleMapping lifecycleMapping = configurationManager.getLifecycleMapping(projectFacade, monitor);
+
+ ThreadBuildContext.setThreadBuildContext(buildContext);
+ try {
+ if(projectFacade.hasValidConfiguration()) {
+ List<AbstractBuildParticipant> participants = lifecycleMapping.getBuildParticipants(projectFacade, monitor);
+ for(InternalBuildParticipant participant : participants) {
+ participant.setMavenProjectFacade(projectFacade);
+ participant.setGetDeltaCallback(getDeltaCallback);
+ participant.setSession(session);
+ participant.setBuildContext(buildContext);
+ try {
+ if(FULL_BUILD == kind || delta != null || participant.callOnEmptyDelta()) {
+ Set<IProject> sub = participant.build(kind, monitor);
+ if(sub != null) {
+ dependencies.addAll(sub);
+ }
+ }
+ } catch(Exception e) {
+ MavenLogger.log("Exception in build participant", e);
+ } finally {
+ participant.setMavenProjectFacade(null);
+ participant.setGetDeltaCallback(null);
+ participant.setSession(null);
+ participant.setBuildContext(null);
+ }
+ }
+ }
+ } catch (CoreException e) {
+ addErrorMarker(e);
+ } finally {
+ ThreadBuildContext.setThreadBuildContext(null);
+ }
+
+ for(File file : buildContext.getFiles()) {
+ IPath path = getProjectRelativePath(project, file);
+ if(path == null) {
+ continue; // odd
+ }
+
+ if(!file.exists()) {
+ IResource resource = project.findMember(path);
+ if (resource != null) {
+ resource.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+ }
+ } else if(file.isDirectory()) {
+ IFolder ifolder = project.getFolder(path);
+ ifolder.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+ } else {
+ IFile ifile = project.getFile(path);
+ ifile.refreshLocal(IResource.DEPTH_ZERO, monitor);
+ }
+ }
+
+ MavenExecutionResult result = session.getResult();
+ if (result.hasExceptions()) {
+ markerManager.addMarkers(pomResource, IMavenConstants.MARKER_BUILD_ID, result);
+ }
+
+ return !dependencies.isEmpty() ? dependencies.toArray(new IProject[dependencies.size()]) : null;
+ }
+ return null;
+ }
+
+ private void addErrorMarker(Exception e) {
+ String msg = e.getMessage();
+ String rootCause = M2EUtils.getRootCauseMessage(e);
+ if(!e.equals(msg)){
+ msg = msg+": "+rootCause; //$NON-NLS-1$
+ }
+
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ IMavenMarkerManager markerManager = plugin.getMavenMarkerManager();
+ markerManager.addMarker(getProject(), IMavenConstants.MARKER_BUILD_ID, msg, 1, IMarker.SEVERITY_ERROR);
+ }
+
+ public static IPath getProjectRelativePath(IProject project, File file) {
+ if(project == null || file == null) {
+ return null;
+ }
+
+ IPath projectPath = project.getLocation();
+ if(projectPath == null) {
+ return null;
+ }
+
+ IPath filePath = new Path(file.getAbsolutePath());
+ if(!projectPath.isPrefixOf(filePath)) {
+ return null;
+ }
+
+ return filePath.removeFirstSegments(projectPath.segmentCount());
+ }
+
+ protected void clean(IProgressMonitor monitor) throws CoreException{
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ MavenProjectManager projectManager = plugin.getMavenProjectManager();
+ IProjectConfigurationManager configurationManager = plugin.getProjectConfigurationManager();
+
+ IProject project = getProject();
+ IMavenMarkerManager markerManager = plugin.getMavenMarkerManager();
+ markerManager.deleteMarkers(project, IMavenConstants.MARKER_BUILD_ID);
+
+ if(project.hasNature(IMavenConstants.NATURE_ID)) {
+ IFile pomResource = project.getFile(IMavenConstants.POM_FILE_NAME);
+ if(pomResource == null) {
+ return;
+ }
+
+ IMavenProjectFacade projectFacade = projectManager.create(getProject(), monitor);
+ if(projectFacade == null) {
+ return;
+ }
+
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+
+ // TODO flush relevant caches
+
+ project.setSessionProperty(BUILD_CONTEXT_KEY, null); // clean context state
+ Map<String, Object> contextState = new HashMap<String, Object>();
+ EclipseBuildContext buildContext = new EclipseBuildContext(project, contextState);
+
+ MavenExecutionRequest request = projectManager.createExecutionRequest(pomResource, projectFacade.getResolverConfiguration(), monitor);
+ MavenSession session = null;
+ try{
+ session = maven.createSession(request, projectFacade.getMavenProject(monitor));
+ } catch(CoreException ce){
+ //the pom cannot be read. don't fill the log full of junk, just add an error marker
+ addErrorMarker(ce);
+ return;
+ }
+ ILifecycleMapping lifecycleMapping = configurationManager.getLifecycleMapping(projectFacade, monitor);
+
+ ThreadBuildContext.setThreadBuildContext(buildContext);
+ try {
+ for (InternalBuildParticipant participant : lifecycleMapping.getBuildParticipants(projectFacade, monitor)) {
+ participant.setMavenProjectFacade(projectFacade);
+ participant.setGetDeltaCallback(getDeltaCallback);
+ participant.setSession(session);
+ try {
+ participant.clean(monitor);
+ } catch (Exception ex) {
+ // TODO Auto-generated catch block
+ MavenLogger.log("Totoally unexpected exception", ex);
+ } finally {
+ participant.setMavenProjectFacade(null);
+ participant.setGetDeltaCallback(null);
+ participant.setSession(null);
+ }
+ }
+ } catch (CoreException e) {
+ addErrorMarker(e);
+ } finally {
+ ThreadBuildContext.setThreadBuildContext(null);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenNature.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenNature.java
new file mode 100644
index 00000000..b3f38f3c
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/MavenNature.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.builder;
+
+import org.eclipse.core.resources.ICommand;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IProjectNature;
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+
+
+public class MavenNature implements IProjectNature {
+ private IProject project;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.resources.IProjectNature#configure()
+ */
+ public void configure() throws CoreException {
+ IProjectDescription desc = project.getDescription();
+ ICommand[] commands = desc.getBuildSpec();
+
+ for(int i = 0; i < commands.length; ++i) {
+ if(commands[i].getBuilderName().equals(IMavenConstants.BUILDER_ID)) {
+ return;
+ }
+ }
+
+ ICommand[] newCommands = new ICommand[commands.length + 1];
+ System.arraycopy(commands, 0, newCommands, 0, commands.length);
+ ICommand command = desc.newCommand();
+ command.setBuilderName(IMavenConstants.BUILDER_ID);
+ newCommands[commands.length] = command;
+ desc.setBuildSpec(newCommands);
+ project.setDescription(desc, null);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.resources.IProjectNature#deconfigure()
+ */
+ public void deconfigure() throws CoreException {
+ IProjectDescription description = getProject().getDescription();
+ ICommand[] commands = description.getBuildSpec();
+ for(int i = 0; i < commands.length; ++i) {
+ if(commands[i].getBuilderName().equals(IMavenConstants.BUILDER_ID)) {
+ ICommand[] newCommands = new ICommand[commands.length - 1];
+ System.arraycopy(commands, 0, newCommands, 0, i);
+ System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1);
+ description.setBuildSpec(newCommands);
+ return;
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.resources.IProjectNature#getProject()
+ */
+ public IProject getProject() {
+ return project;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.resources.IProjectNature#setProject(org.eclipse.core.resources.IProject)
+ */
+ public void setProject(IProject project) {
+ this.project = project;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/ResourceScanner.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/ResourceScanner.java
new file mode 100644
index 00000000..eff507d3
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/builder/ResourceScanner.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.builder;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceVisitor;
+import org.eclipse.core.runtime.CoreException;
+
+import org.codehaus.plexus.util.AbstractScanner;
+
+/**
+ * WorkspaceScanner
+ *
+ * @author igor
+ */
+public class ResourceScanner extends AbstractScanner {
+
+ protected final IResource resource;
+
+ protected final List<String> includedDirectories = new ArrayList<String>();
+
+ protected final List<String> includedFiles = new ArrayList<String>();
+
+ public ResourceScanner(IResource resource) {
+ this.resource = resource;
+ }
+
+ public String[] getIncludedDirectories() {
+ return includedDirectories.toArray(new String[includedDirectories.size()]);
+ }
+
+ public String[] getIncludedFiles() {
+ return includedFiles.toArray(new String[includedFiles.size()]);
+ }
+
+ public void scan() {
+ try {
+ setupDefaultFilters();
+ scanResource();
+ } catch(CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private void scanResource() throws CoreException {
+ resource.accept(new IResourceVisitor() {
+
+ public boolean visit(IResource resource) {
+ String relpath = getRelativePath(resource);
+ if (isIncluded(relpath) && !isExcluded(relpath)) {
+ if (resource instanceof IContainer) {
+ includedDirectories.add(relpath);
+ } else {
+ includedFiles.add(relpath);
+ }
+ return true;
+ } else if (resource instanceof IFolder) {
+ return couldHoldIncluded(relpath);
+ }
+
+ return false;
+ }
+
+ });
+ }
+
+ protected String getRelativePath(IResource resource) {
+ return resource.getFullPath().removeFirstSegments(this.resource.getFullPath().segmentCount()).toOSString();
+ }
+
+ public File getBasedir() {
+ return resource.getLocation().toFile();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/console/ConsoleDocument.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/console/ConsoleDocument.java
new file mode 100644
index 00000000..77ccfa1b
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/console/ConsoleDocument.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.console;
+
+/**
+ * Simple circular buffer that stores a fix number of lines.
+ */
+// TODO consider use standard ConsoleDocument
+public class ConsoleDocument {
+ public static final int COMMAND = 0; // command text
+ public static final int MESSAGE = 1; // message received
+ public static final int ERROR = 2; // error received
+ public static final int STATUS = 3; // status text
+ public static final int DELIMITER = 4; // delimiter text between runs
+
+ private int[] lineTypes;
+ private String[] lines;
+
+ private int writeIndex = 0;
+ private int readIndex = 0;
+
+ private static final int BUFFER_SIZE = 200;
+
+ protected static class ConsoleLine {
+ public String line;
+ public int type;
+ ConsoleLine(String line, int type) {
+ this.line = line;
+ this.type = type;
+ }
+ }
+
+ /**
+ * Creates an empty console document.
+ */
+ public ConsoleDocument() {
+ }
+
+ /**
+ * Clears the console document.
+ */
+ public void clear() {
+ lineTypes = null;
+ lines = null;
+ writeIndex = 0;
+ readIndex = 0;
+ }
+
+ /**
+ * Appends a line of the specified type to the end of the console.
+ */
+ public void appendConsoleLine(int type, String line) {
+ if(lines == null) {
+ lines = new String[BUFFER_SIZE];
+ lineTypes = new int[BUFFER_SIZE];
+ }
+ lines[writeIndex] = line;
+ lineTypes[writeIndex] = type;
+
+ if(++writeIndex >= BUFFER_SIZE) {
+ writeIndex = 0;
+ }
+ if(writeIndex == readIndex) {
+ if(++readIndex >= BUFFER_SIZE) {
+ readIndex = 0;
+ }
+ }
+ }
+
+ public ConsoleLine[] getLines() {
+ if(isEmpty()) return new ConsoleLine[0];
+ ConsoleLine[] docLines = new ConsoleLine[readIndex > writeIndex ? BUFFER_SIZE : writeIndex];
+ int index = readIndex;
+ for (int i = 0; i < docLines.length; i++) {
+ docLines[i] = new ConsoleLine(lines[index], lineTypes[index]);
+ if (++index >= BUFFER_SIZE) {
+ index = 0;
+ }
+ }
+ return docLines;
+ }
+
+ public boolean isEmpty() {
+ return writeIndex == readIndex;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/console/MavenConsoleImpl.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/console/MavenConsoleImpl.java
new file mode 100644
index 00000000..0b28a509
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/console/MavenConsoleImpl.java
@@ -0,0 +1,404 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.console;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import com.ibm.icu.text.DateFormat;
+import com.ibm.icu.util.ULocale;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.console.ConsolePlugin;
+import org.eclipse.ui.console.IConsole;
+import org.eclipse.ui.console.IConsoleListener;
+import org.eclipse.ui.console.IConsoleManager;
+import org.eclipse.ui.console.IOConsole;
+import org.eclipse.ui.console.IOConsoleOutputStream;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConsoleListener;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
+
+
+/**
+ * Maven Console implementation
+ *
+ * @author Dmitri Maximovich
+ */
+public class MavenConsoleImpl extends IOConsole implements MavenConsole, IPropertyChangeListener {
+
+ private boolean initialized = false;
+
+ // console is visible in the Console view
+ private boolean visible = false;
+
+ private ConsoleDocument consoleDocument;
+
+ // created colors for each line type - must be disposed at shutdown
+ private Color commandColor;
+
+ private Color messageColor;
+
+ private Color errorColor;
+
+ // streams for each command type - each stream has its own color
+ private IOConsoleOutputStream commandStream;
+
+ private IOConsoleOutputStream messageStream;
+
+ private IOConsoleOutputStream errorStream;
+ private static final String TITLE = Messages.MavenConsoleImpl_title;
+
+ private List<IMavenConsoleListener> listeners = new CopyOnWriteArrayList<IMavenConsoleListener>();
+
+ public MavenConsoleImpl(ImageDescriptor imageDescriptor) {
+ super(TITLE, imageDescriptor);
+ this.setConsoleDocument(new ConsoleDocument());
+ }
+
+ protected void init() {
+ super.init();
+
+ // Ensure that initialization occurs in the UI thread
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ JFaceResources.getFontRegistry().addListener(MavenConsoleImpl.this);
+ initializeConsoleStreams(Display.getDefault());
+ dumpConsole();
+ }
+ });
+ }
+
+ /*
+ * Initialize three streams of the console. Must be called from the UI thread, so synchronization is unnecessary.
+ */
+ protected void initializeConsoleStreams(Display display) {
+ if(!initialized) {
+ setCommandStream(newOutputStream());
+ setErrorStream(newOutputStream());
+ setMessageStream(newOutputStream());
+
+ // TODO convert this to use themes
+ // install colors
+ commandColor = new Color(display, new RGB(0, 0, 0));
+ messageColor = new Color(display, new RGB(0, 0, 255));
+ errorColor = new Color(display, new RGB(255, 0, 0));
+
+ getCommandStream().setColor(commandColor);
+ getMessageStream().setColor(messageColor);
+ getErrorStream().setColor(errorColor);
+
+ // install font
+ setFont(JFaceResources.getFontRegistry().get("pref_console_font")); //$NON-NLS-1$
+
+ initialized = true;
+ }
+ }
+
+ /**
+ * Is always called from main thread, so synchronization not necessary
+ */
+ protected void dumpConsole() {
+ setVisible(true);
+ ConsoleDocument.ConsoleLine[] lines = getConsoleDocument().getLines();
+ for(int i = 0; i < lines.length; i++ ) {
+ ConsoleDocument.ConsoleLine line = lines[i];
+ appendLine(line.type, line.line);
+ }
+ getConsoleDocument().clear();
+ }
+
+ private void appendLine(final int type, final String line) {
+ show(false);
+ //the synchronization here caused a deadlock. since the writes are simply appending to the output stream
+ //or the document, just doing it on the main thread to avoid deadlocks and or corruption of the
+ //document or output stream
+ Display.getDefault().asyncExec(new Runnable(){
+ public void run(){
+ if(isVisible()) {
+ try {
+ switch(type) {
+ case ConsoleDocument.COMMAND:
+ getCommandStream().write(line);
+ getCommandStream().write('\n');
+ break;
+ case ConsoleDocument.MESSAGE:
+ getMessageStream().write(line);
+ getMessageStream().write('\n');
+ break;
+ case ConsoleDocument.ERROR:
+ getErrorStream().write(line);
+ getErrorStream().write('\n');
+ break;
+ }
+ } catch(IOException ex) {
+ MavenLogger.log("Console error", ex);
+ }
+ } else {
+ getConsoleDocument().appendConsoleLine(type, line);
+ }
+ }
+ });
+ }
+
+ /**
+ * Show the console.
+ *
+ * @param showNoMatterWhat ignore preferences if <code>true</code>
+ */
+ public void show(boolean showNoMatterWhat) {
+ if(showNoMatterWhat) {
+ if(!isVisible()) {
+ showConsole();
+ } else {
+ ConsolePlugin.getDefault().getConsoleManager().showConsoleView(this);
+ }
+ }
+ }
+
+ public void showConsole() {
+ boolean exists = false;
+ IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager();
+ for(IConsole element : manager.getConsoles()) {
+ if(this == element) {
+ exists = true;
+ }
+ }
+ if(!exists) {
+ manager.addConsoles(new IConsole[] {this});
+ }
+ manager.showConsoleView(this);
+ }
+
+ public void closeConsole() {
+ IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager();
+ manager.removeConsoles(new IConsole[] {this});
+ ConsolePlugin.getDefault().getConsoleManager().addConsoleListener(this.newLifecycle());
+ }
+
+
+ public void propertyChange(PropertyChangeEvent event) {
+ // font changed
+ setFont(JFaceResources.getFontRegistry().get("pref_console_font")); //$NON-NLS-1$
+ }
+
+ private void bringConsoleToFront() {
+ if(PlatformUI.isWorkbenchRunning()) {
+ IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager();
+ if(!isVisible()) {
+ manager.addConsoles(new IConsole[] {this});
+ }
+ manager.showConsoleView(this);
+ }
+ }
+
+ // Called when console is removed from the console view
+ protected void dispose() {
+ // Here we can't call super.dispose() because we actually want the partitioner to remain
+ // connected, but we won't show lines until the console is added to the console manager
+ // again.
+ Display.getDefault().asyncExec(new Runnable(){
+ public void run(){
+ setVisible(false);
+ JFaceResources.getFontRegistry().removeListener(MavenConsoleImpl.this);
+ }
+ });
+ }
+
+ public void shutdown() {
+ // Call super dispose because we want the partitioner to be
+ // disconnected.
+ super.dispose();
+ if(commandColor != null) {
+ commandColor.dispose();
+ }
+ if(messageColor != null) {
+ messageColor.dispose();
+ }
+ if(errorColor != null) {
+ errorColor.dispose();
+ }
+ }
+
+ private DateFormat getDateFormat() {
+ return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, ULocale.getDefault());
+ }
+
+ // MavenConsole
+
+ public void logMessage(String message) {
+ if(showConsoleOnOutput()){
+ bringConsoleToFront();
+ }
+ appendLine(ConsoleDocument.MESSAGE, getDateFormat().format(new Date()) + ": " + message);
+
+ for(IMavenConsoleListener listener : listeners) {
+ try {
+ listener.loggingMessage(message);
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void logError(String message) {
+ if(showConsoleOnError()){
+ bringConsoleToFront();
+ }
+ appendLine(ConsoleDocument.ERROR, getDateFormat().format(new Date()) + ": " + message); //$NON-NLS-1$
+
+ for(IMavenConsoleListener listener : listeners) {
+ try {
+ listener.loggingError(message);
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public boolean showConsoleOnError(){
+ return MavenPlugin.getDefault().getPreferenceStore().getBoolean(MavenPreferenceConstants.P_SHOW_CONSOLE_ON_ERR);
+ }
+
+ public boolean showConsoleOnOutput(){
+ return MavenPlugin.getDefault().getPreferenceStore().getBoolean(MavenPreferenceConstants.P_SHOW_CONSOLE_ON_OUTPUT);
+ }
+ public IConsoleListener newLifecycle() {
+ return new MavenConsoleLifecycle();
+ }
+
+ /**
+ * @param commandStream The commandStream to set.
+ */
+ protected void setCommandStream(IOConsoleOutputStream commandStream) {
+ this.commandStream = commandStream;
+ }
+
+ /**
+ * @return Returns the commandStream.
+ */
+ protected IOConsoleOutputStream getCommandStream() {
+ return commandStream;
+ }
+
+ /**
+ * @param messageStream The messageStream to set.
+ */
+ protected void setMessageStream(IOConsoleOutputStream messageStream) {
+ this.messageStream = messageStream;
+ }
+
+ /**
+ * @return Returns the messageStream.
+ */
+ protected IOConsoleOutputStream getMessageStream() {
+ return messageStream;
+ }
+
+ /**
+ * @param errorStream The errorStream to set.
+ */
+ protected void setErrorStream(IOConsoleOutputStream errorStream) {
+ this.errorStream = errorStream;
+ }
+
+ /**
+ * @return Returns the errorStream.
+ */
+ protected IOConsoleOutputStream getErrorStream() {
+ return errorStream;
+ }
+
+ /**
+ * @param visible The visible to set.
+ */
+ protected void setVisible(boolean visible) {
+ this.visible = visible;
+ }
+
+ /**
+ * @return Returns the visible.
+ */
+ protected boolean isVisible() {
+ return visible;
+ }
+
+ /**
+ * @param consoleDocument The consoleDocument to set.
+ */
+ private void setConsoleDocument(ConsoleDocument consoleDocument) {
+ this.consoleDocument = consoleDocument;
+ }
+
+ /**
+ * @return Returns the consoleDocument.
+ */
+ protected ConsoleDocument getConsoleDocument() {
+ return consoleDocument;
+ }
+
+ /**
+ * Used to notify this console of lifecycle methods <code>init()</code> and <code>dispose()</code>.
+ */
+ public class MavenConsoleLifecycle implements org.eclipse.ui.console.IConsoleListener {
+
+ public void consolesAdded(IConsole[] consoles) {
+ for(int i = 0; i < consoles.length; i++ ) {
+ IConsole console = consoles[i];
+ if(console == MavenConsoleImpl.this) {
+ init();
+ }
+ }
+
+ }
+
+ public void consolesRemoved(IConsole[] consoles) {
+ for(int i = 0; i < consoles.length; i++ ) {
+ IConsole console = consoles[i];
+ if(console == MavenConsoleImpl.this) {
+ ConsolePlugin.getDefault().getConsoleManager().removeConsoleListener(this);
+ dispose();
+ }
+ }
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.core.MavenConsole#addMavenConsoleListener(org.eclipse.m2e.core.IMavenConsoleListener)
+ */
+ public void addMavenConsoleListener(IMavenConsoleListener listener) {
+ listeners.remove(listener);
+ listeners.add(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.core.MavenConsole#removeMavenConsoleListener(org.eclipse.m2e.core.IMavenConsoleListener)
+ */
+ public void removeMavenConsoleListener(IMavenConsoleListener listener) {
+ listeners.remove(listener);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomFileContentDescriber.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomFileContentDescriber.java
new file mode 100644
index 00000000..49c9a868
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomFileContentDescriber.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.content;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import org.eclipse.core.runtime.content.IContentDescription;
+
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * A content describer for POM files.
+ *
+ * @see org.eclipse.ant.internal.core.contentDescriber.AntBuildfileContentDescriber
+ * @author Herve Boutemy
+ * @since 0.9.6
+ */
+public final class PomFileContentDescriber extends XMLContentDescriber {
+ /**
+ * Determines the validation status for the given contents.
+ *
+ * @param contents the contents to be evaluated
+ * @return one of the following:<ul>
+ * <li><code>VALID</code></li>,
+ * <li><code>INVALID</code></li>,
+ * <li><code>INDETERMINATE</code></li>
+ * </ul>
+ * @throws IOException
+ */
+ private int checkCriteria(InputSource contents) throws IOException {
+ PomHandler pomHandler = new PomHandler();
+ try {
+ if(!pomHandler.parseContents(contents)) {
+ return INDETERMINATE;
+ }
+ } catch(SAXException e) {
+ // we may be handed any kind of contents... it is normal we fail to parse
+ return INDETERMINATE;
+ } catch(ParserConfigurationException e) {
+ // some bad thing happened - force this describer to be disabled
+ throw new RuntimeException(Messages.PomFileContentDescriber_error);
+ }
+
+ // Check to see if we matched our criteria.
+ if(pomHandler.hasRootProjectElement()) {
+ if(pomHandler.hasArtifactIdElement()) {
+ //project and artifactId element
+ return VALID;
+ }
+ //only a top level project element: maybe a POM file, but maybe an Ant buildfile, a site descriptor, ...
+ return INDETERMINATE;
+ }
+ return INDETERMINATE;
+ }
+
+ @Override
+ public int describe(InputStream contents, IContentDescription description) throws IOException {
+ // call the basic XML describer to do basic recognition
+ if(super.describe(contents, description) == INVALID) {
+ return INVALID;
+ }
+ // super.describe will have consumed some chars, need to rewind
+ contents.reset();
+ // Check to see if we matched our criteria.
+ return checkCriteria(new InputSource(contents));
+ }
+
+ @Override
+ public int describe(Reader contents, IContentDescription description) throws IOException {
+ // call the basic XML describer to do basic recognition
+ if(super.describe(contents, description) == INVALID) {
+ return INVALID;
+ }
+ // super.describe will have consumed some chars, need to rewind
+ contents.reset();
+ // Check to see if we matched our criteria.
+ return checkCriteria(new InputSource(contents));
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomHandler.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomHandler.java
new file mode 100644
index 00000000..3ff2db65
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomHandler.java
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.content;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+
+/**
+ * An xml event handler for detecting the project top-level element in a POM file. Also records whether a default
+ * attribute is present for the project and if any typical Maven elements are present.
+ *
+ * @see org.eclipse.ant.internal.core.contentDescriber.AntHandler
+ * @author Herve Boutemy
+ * @since 0.9.6
+ */
+public final class PomHandler extends DefaultHandler {
+ /**
+ * An exception indicating that the parsing should stop.
+ */
+ private class StopParsingException extends SAXException {
+ /**
+ * All serializable objects should have a stable serialVersionUID
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs an instance of <code>StopParsingException</code> with a <code>null</code> detail message.
+ */
+ public StopParsingException() {
+ super((String) null);
+ }
+ }
+
+ private static final String PROJECT = "project"; //$NON-NLS-1$
+
+ private static final String ARTIFACTID = "artifactId"; //$NON-NLS-1$
+
+ /**
+ * This is the name of the top-level element found in the XML file. This member variable is <code>null</code> unless
+ * the file has been parsed successful to the point of finding the top-level element.
+ */
+ private String fTopElementFound = null;
+
+ private SAXParserFactory fFactory;
+
+ private boolean fArtifactIdFound = false;
+
+ private int fLevel = -1;
+
+ /**
+ * Creates a new SAX parser for use within this instance.
+ *
+ * @return The newly created parser.
+ * @throws ParserConfigurationException If a parser of the given configuration cannot be created.
+ * @throws SAXException If something in general goes wrong when creating the parser.
+ */
+ private final SAXParser createParser(SAXParserFactory parserFactory) throws ParserConfigurationException,
+ SAXException, SAXNotRecognizedException, SAXNotSupportedException {
+ // Initialize the parser.
+ final SAXParser parser = parserFactory.newSAXParser();
+ final XMLReader reader = parser.getXMLReader();
+ // disable DTD validation
+ try {
+ // be sure validation is "off" or the feature to ignore DTD's will not apply
+ reader.setFeature("http://xml.org/sax/features/validation", false); //$NON-NLS-1$
+ reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$
+ } catch(SAXNotRecognizedException e) {
+ // not a big deal if the parser does not recognize the features
+ } catch(SAXNotSupportedException e) {
+ // not a big deal if the parser does not support the features
+ }
+ return parser;
+ }
+
+ private SAXParserFactory getFactory() {
+ synchronized(this) {
+ if(fFactory != null) {
+ return fFactory;
+ }
+ fFactory = SAXParserFactory.newInstance();
+ fFactory.setNamespaceAware(true);
+ }
+ return fFactory;
+ }
+
+ protected boolean parseContents(InputSource contents) throws IOException, ParserConfigurationException, SAXException {
+ // Parse the file into we have what we need (or an error occurs).
+ try {
+ fFactory = getFactory();
+ if(fFactory == null) {
+ return false;
+ }
+ final SAXParser parser = createParser(fFactory);
+ // to support external entities specified as relative URIs (see bug 63298)
+ contents.setSystemId("/"); //$NON-NLS-1$
+ parser.parse(contents, this);
+ } catch(StopParsingException e) {
+ // Abort the parsing normally. Fall through...
+ }
+ return true;
+ }
+
+ /*
+ * Resolve external entity definitions to an empty string. This is to speed
+ * up processing of files with external DTDs. Not resolving the contents
+ * of the DTD is ok, as only the System ID of the DTD declaration is used.
+ * @see org.xml.sax.helpers.DefaultHandler#resolveEntity(java.lang.String, java.lang.String)
+ */
+ @Override
+ public InputSource resolveEntity(String publicId, String systemId) {
+ return new InputSource(new StringReader("")); //$NON-NLS-1$
+ }
+
+
+ @Override
+ public final void startElement(final String uri, final String elementName, final String qualifiedName,
+ final Attributes attributes) throws SAXException {
+ fLevel++ ;
+ if(fTopElementFound == null) {
+ fTopElementFound = elementName;
+ if(!hasRootProjectElement()) {
+ throw new StopParsingException();
+ }
+ }
+ if(fLevel == 1 && ARTIFACTID.equals(elementName)) {
+ fArtifactIdFound = true;
+ throw new StopParsingException();
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ super.endElement(uri, localName, qName);
+ fLevel-- ;
+ }
+
+ protected boolean hasRootProjectElement() {
+ return PROJECT.equals(fTopElementFound);
+ }
+
+ protected boolean hasArtifactIdElement() {
+ return fArtifactIdFound;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/TextContentDescriber.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/TextContentDescriber.java
new file mode 100644
index 00000000..bfe4da15
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/TextContentDescriber.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.content;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.content.IContentDescription;
+import org.eclipse.core.runtime.content.ITextContentDescriber;
+
+/**
+ * A copy of org.eclipse.core.internal.content.TextContentDescriber to avoid internal API use.
+ *
+ * This class provides internal basis for text-based content describers.
+ *
+ * <p>
+ * Note: do not add protected/public members to this class if you don't intend to
+ * make them public API.
+ * </p>
+ *
+ * @see org.eclipse.core.runtime.content.XMLRootElementContentDescriber2
+ * @since 3.0
+ */
+class TextContentDescriber implements ITextContentDescriber {
+
+ private final static QualifiedName[] SUPPORTED_OPTIONS = {IContentDescription.BYTE_ORDER_MARK};
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.content.ITextContentDescriber#describe(java.io.Reader, org.eclipse.core.runtime.content.IContentDescription)
+ */
+ @SuppressWarnings("unused")
+ public int describe(Reader contents, IContentDescription description) throws IOException {
+ // we want to be pretty loose on detecting the text content type
+ return INDETERMINATE;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.content.IContentDescriber#describe(java.io.InputStream, org.eclipse.core.runtime.content.IContentDescription)
+ */
+ public int describe(InputStream contents, IContentDescription description) throws IOException {
+ if (description == null || !description.isRequested(IContentDescription.BYTE_ORDER_MARK))
+ return INDETERMINATE;
+ byte[] bom = getByteOrderMark(contents);
+ if (bom != null)
+ description.setProperty(IContentDescription.BYTE_ORDER_MARK, bom);
+ // we want to be pretty loose on detecting the text content type
+ return INDETERMINATE;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.content.IContentDescriber#getSupportedOptions()
+ */
+ public QualifiedName[] getSupportedOptions() {
+ return SUPPORTED_OPTIONS;
+ }
+
+ byte[] getByteOrderMark(InputStream input) throws IOException {
+ int first = input.read();
+ if (first == 0xEF) {
+ //look for the UTF-8 Byte Order Mark (BOM)
+ int second = input.read();
+ int third = input.read();
+ if (second == 0xBB && third == 0xBF)
+ return IContentDescription.BOM_UTF_8;
+ } else if (first == 0xFE) {
+ //look for the UTF-16 BOM
+ if (input.read() == 0xFF)
+ return IContentDescription.BOM_UTF_16BE;
+ } else if (first == 0xFF) {
+ if (input.read() == 0xFE)
+ return IContentDescription.BOM_UTF_16LE;
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/XMLContentDescriber.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/XMLContentDescriber.java
new file mode 100644
index 00000000..ed115a0a
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/XMLContentDescriber.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.content;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.content.IContentDescription;
+import org.eclipse.core.runtime.content.ITextContentDescriber;
+
+/**
+ * A copy of org.eclipse.core.internal.content.XMLContentDescriber to avoid internal API use.
+ *
+ * A content interpreter for XML files.
+ * This class provides internal basis for XML-based content describers.
+ * <p>
+ * Note: do not add protected/public members to this class if you don't intend to
+ * make them public API.
+ * </p>
+ *
+ * @see org.eclipse.core.runtime.content.XMLRootElementContentDescriber2
+ * @see "http://www.w3.org/TR/REC-xml *"
+ */
+class XMLContentDescriber extends TextContentDescriber implements ITextContentDescriber {
+ private static final QualifiedName[] SUPPORTED_OPTIONS = new QualifiedName[] {IContentDescription.CHARSET, IContentDescription.BYTE_ORDER_MARK};
+ private static final String ENCODING = "encoding="; //$NON-NLS-1$
+ private static final String XML_PREFIX = "<?xml "; //$NON-NLS-1$
+
+ public int describe(InputStream input, IContentDescription description) throws IOException {
+ byte[] bom = getByteOrderMark(input);
+ String xmlDeclEncoding = "UTF-8"; //$NON-NLS-1$
+ input.reset();
+ if (bom != null) {
+ if (bom == IContentDescription.BOM_UTF_16BE)
+ xmlDeclEncoding = "UTF-16BE"; //$NON-NLS-1$
+ else if (bom == IContentDescription.BOM_UTF_16LE)
+ xmlDeclEncoding = "UTF-16LE"; //$NON-NLS-1$
+ // skip BOM to make comparison simpler
+ input.skip(bom.length);
+ // set the BOM in the description if requested
+ if (description != null && description.isRequested(IContentDescription.BYTE_ORDER_MARK))
+ description.setProperty(IContentDescription.BYTE_ORDER_MARK, bom);
+ }
+ byte[] xmlPrefixBytes = XML_PREFIX.getBytes(xmlDeclEncoding);
+ byte[] prefix = new byte[xmlPrefixBytes.length];
+ if (input.read(prefix) < prefix.length)
+ // there is not enough info to say anything
+ return INDETERMINATE;
+ for (int i = 0; i < prefix.length; i++)
+ if (prefix[i] != xmlPrefixBytes[i])
+ // we don't have a XMLDecl... there is not enough info to say anything
+ return INDETERMINATE;
+ if (description == null)
+ return VALID;
+ // describe charset if requested
+ if (description.isRequested(IContentDescription.CHARSET)) {
+ String fullXMLDecl = readFullXMLDecl(input, xmlDeclEncoding);
+ if (fullXMLDecl != null) {
+ String charset = getCharset(fullXMLDecl);
+ if (charset != null && !"UTF-8".equalsIgnoreCase(charset)) //$NON-NLS-1$
+ // only set property if value is not default (avoid using a non-default content description)
+ description.setProperty(IContentDescription.CHARSET, getCharset(fullXMLDecl));
+ }
+ }
+ return VALID;
+ }
+
+ private String readFullXMLDecl(InputStream input, String unicodeEncoding) throws IOException {
+ byte[] xmlDecl = new byte[100];
+ int c = 0;
+ // looks for XMLDecl ending char (?)
+ int read = 0;
+ while (read < xmlDecl.length && (c = input.read()) != -1 && c != '?')
+ xmlDecl[read++] = (byte) c;
+ return c == '?' ? new String(xmlDecl, 0, read, unicodeEncoding) : null;
+ }
+
+ public int describe(Reader input, IContentDescription description) throws IOException {
+ BufferedReader reader = new BufferedReader(input);
+ String line = reader.readLine();
+ // end of stream
+ if (line == null)
+ return INDETERMINATE;
+ // XMLDecl should be the first string (no blanks allowed)
+ if (!line.startsWith(XML_PREFIX))
+ return INDETERMINATE;
+ if (description == null)
+ return VALID;
+ // describe charset if requested
+ if ((description.isRequested(IContentDescription.CHARSET)))
+ description.setProperty(IContentDescription.CHARSET, getCharset(line));
+ return VALID;
+ }
+
+ private String getCharset(String firstLine) {
+ int encodingPos = firstLine.indexOf(ENCODING);
+ if (encodingPos == -1)
+ return null;
+ char quoteChar = '"';
+ int firstQuote = firstLine.indexOf(quoteChar, encodingPos);
+ if (firstQuote == -1) {
+ quoteChar = '\'';
+ firstQuote = firstLine.indexOf(quoteChar, encodingPos);
+ }
+ if (firstQuote == -1 || firstLine.length() == firstQuote - 1)
+ return null;
+ int secondQuote = firstLine.indexOf(quoteChar, firstQuote + 1);
+ if (secondQuote == -1)
+ return null;
+ return firstLine.substring(firstQuote + 1, secondQuote);
+ }
+
+ public QualifiedName[] getSupportedOptions() {
+ return SUPPORTED_OPTIONS;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/AbstractTransferListenerAdapter.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/AbstractTransferListenerAdapter.java
new file mode 100644
index 00000000..22d1f714
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/AbstractTransferListenerAdapter.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.osgi.util.NLS;
+
+import org.apache.maven.wagon.WagonConstants;
+
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * AbstractTransferListenerAdapter
+ *
+ * @author igor
+ */
+abstract class AbstractTransferListenerAdapter {
+
+ protected final MavenImpl maven;
+
+ protected final IProgressMonitor monitor;
+
+ protected final MavenConsole console;
+
+ protected long complete = 0;
+
+ private static final String[] units = {Messages.AbstractTransferListenerAdapter_byte, Messages.AbstractTransferListenerAdapter_kb, Messages.AbstractTransferListenerAdapter_mb};
+
+ protected AbstractTransferListenerAdapter(MavenImpl maven, IProgressMonitor monitor, MavenConsole console) {
+ this.maven = maven;
+ this.monitor = monitor == null ? new NullProgressMonitor() : monitor;
+ this.console = console;
+ }
+
+ protected void formatBytes(long n, StringBuffer sb) {
+ int i = 0;
+ while(n >= 1024 && ++i < units.length)
+ n >>= 10;
+
+ sb.append(n);
+ sb.append(units[i]);
+ }
+
+ protected void transferInitiated(String artifactUrl) {
+ this.complete = 0;
+
+ if (artifactUrl != null) {
+ monitor.subTask(artifactUrl);
+ }
+ }
+
+ protected void transferStarted(String artifactUrl) {
+ console.logMessage(NLS.bind("Downloading {0}", artifactUrl));
+ // monitor.beginTask("0% "+e.getWagon().getRepository()+"/"+e.getResource().getName(), IProgressMonitor.UNKNOWN);
+ monitor.subTask(Messages.AbstractTransferListenerAdapter_4 + artifactUrl);
+ }
+
+ protected void transferProgress(String artifactUrl, long total, int length) {
+ if(monitor.isCanceled()) {
+ throw new OperationCanceledException(Messages.AbstractTransferListenerAdapter_cancelled);
+ }
+
+ complete += length;
+
+ StringBuffer sb = new StringBuffer();
+
+ formatBytes(complete, sb);
+ if(total != WagonConstants.UNKNOWN_LENGTH) {
+ sb.append('/');
+ formatBytes(total, sb);
+ if (total > 0) {
+ sb.append(" (");
+ sb.append(100l * complete / total);
+ sb.append("%)");
+ }
+ }
+ sb.append(' ');
+
+ monitor.subTask(sb.toString() + artifactUrl);
+ }
+
+ protected void transferCompleted(String artifactUrl) {
+ console.logMessage(NLS.bind("Downloaded {0}", artifactUrl));
+
+ // monitor.subTask("100% "+e.getWagon().getRepository()+"/"+e.getResource().getName());
+ monitor.subTask(""); //$NON-NLS-1$
+ }
+
+ protected void transferError(String artifactUrl, Exception exception) {
+ console.logMessage(NLS.bind("Unable to download {0} : {1}", artifactUrl, exception));
+ monitor.subTask(NLS.bind(Messages.AbstractTransferListenerAdapter_subtask, artifactUrl));
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ArtifactTransferListenerAdapter.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ArtifactTransferListenerAdapter.java
new file mode 100644
index 00000000..9562cb9c
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ArtifactTransferListenerAdapter.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.sonatype.aether.transfer.TransferEvent;
+import org.sonatype.aether.transfer.TransferListener;
+
+import org.eclipse.m2e.core.core.MavenConsole;
+
+/**
+ * ArtifactTransferListenerAdapter
+ *
+ * @author igor
+ */
+public class ArtifactTransferListenerAdapter extends AbstractTransferListenerAdapter implements
+ TransferListener {
+
+ ArtifactTransferListenerAdapter(MavenImpl maven, IProgressMonitor monitor, MavenConsole console) {
+ super(maven, monitor, console);
+ }
+
+ public void transferInitiated(TransferEvent event) {
+ transferInitiated(event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
+ }
+
+ public void transferProgressed(TransferEvent event) {
+ long total = event.getResource().getContentLength();
+ String artifactUrl = event.getResource().getRepositoryUrl() + event.getResource().getResourceName();
+
+ transferProgress(artifactUrl, total, event.getDataBuffer().remaining());
+ }
+
+ public void transferStarted(TransferEvent event) {
+ transferStarted(event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
+ }
+
+ public void transferCorrupted(TransferEvent event) {
+ }
+
+ public void transferSucceeded(TransferEvent event) {
+ transferCompleted(event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
+ }
+
+ public void transferFailed(TransferEvent event) {
+ transferCompleted(event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ContextRepositorySystemSession.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ContextRepositorySystemSession.java
new file mode 100644
index 00000000..7ac41337
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ContextRepositorySystemSession.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import org.sonatype.aether.RepositorySystemSession;
+
+public interface ContextRepositorySystemSession extends RepositorySystemSession {
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ContextRepositorySystemSessionImpl.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ContextRepositorySystemSessionImpl.java
new file mode 100644
index 00000000..840e1938
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ContextRepositorySystemSessionImpl.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import java.util.Map;
+
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+
+import org.apache.maven.plugin.LegacySupport;
+
+import org.sonatype.aether.RepositoryCache;
+import org.sonatype.aether.RepositoryListener;
+import org.sonatype.aether.RepositorySystemSession;
+import org.sonatype.aether.SessionData;
+import org.sonatype.aether.artifact.ArtifactTypeRegistry;
+import org.sonatype.aether.collection.DependencyGraphTransformer;
+import org.sonatype.aether.collection.DependencyManager;
+import org.sonatype.aether.collection.DependencySelector;
+import org.sonatype.aether.collection.DependencyTraverser;
+import org.sonatype.aether.repository.AuthenticationSelector;
+import org.sonatype.aether.repository.LocalRepository;
+import org.sonatype.aether.repository.LocalRepositoryManager;
+import org.sonatype.aether.repository.MirrorSelector;
+import org.sonatype.aether.repository.ProxySelector;
+import org.sonatype.aether.repository.WorkspaceReader;
+import org.sonatype.aether.transfer.TransferListener;
+
+
+@Component(role = ContextRepositorySystemSession.class)
+public class ContextRepositorySystemSessionImpl implements ContextRepositorySystemSession {
+
+ @Requirement
+ private LegacySupport context;
+
+ private RepositorySystemSession getSession() {
+ RepositorySystemSession session = context.getRepositorySession();
+ if(session == null) {
+ throw new IllegalStateException("no context maven session"); //$NON-NLS-1$
+ }
+ return session;
+ }
+
+ public ArtifactTypeRegistry getArtifactTypeRegistry() {
+ return getSession().getArtifactTypeRegistry();
+ }
+
+ public AuthenticationSelector getAuthenticationSelector() {
+ return getSession().getAuthenticationSelector();
+ }
+
+ public RepositoryCache getCache() {
+ return getSession().getCache();
+ }
+
+ public String getChecksumPolicy() {
+ return getSession().getChecksumPolicy();
+ }
+
+ public Map<String, Object> getConfigProperties() {
+ return getSession().getConfigProperties();
+ }
+
+ public SessionData getData() {
+ return getSession().getData();
+ }
+
+ public DependencyGraphTransformer getDependencyGraphTransformer() {
+ return getSession().getDependencyGraphTransformer();
+ }
+
+ public DependencyManager getDependencyManager() {
+ return getSession().getDependencyManager();
+ }
+
+ public DependencySelector getDependencySelector() {
+ return getSession().getDependencySelector();
+ }
+
+ public DependencyTraverser getDependencyTraverser() {
+ return getSession().getDependencyTraverser();
+ }
+
+ public LocalRepository getLocalRepository() {
+ return getSession().getLocalRepository();
+ }
+
+ public LocalRepositoryManager getLocalRepositoryManager() {
+ return getSession().getLocalRepositoryManager();
+ }
+
+ public MirrorSelector getMirrorSelector() {
+ return getSession().getMirrorSelector();
+ }
+
+ public ProxySelector getProxySelector() {
+ return getSession().getProxySelector();
+ }
+
+ public RepositoryListener getRepositoryListener() {
+ return getSession().getRepositoryListener();
+ }
+
+ public Map<String, String> getSystemProperties() {
+ return getSession().getSystemProperties();
+ }
+
+ public TransferListener getTransferListener() {
+ return getSession().getTransferListener();
+ }
+
+ public String getUpdatePolicy() {
+ return getSession().getUpdatePolicy();
+ }
+
+ public Map<String, String> getUserProperties() {
+ return getSession().getUserProperties();
+ }
+
+ public WorkspaceReader getWorkspaceReader() {
+ return getSession().getWorkspaceReader();
+ }
+
+ public boolean isIgnoreInvalidArtifactDescriptor() {
+ return getSession().isIgnoreInvalidArtifactDescriptor();
+ }
+
+ public boolean isIgnoreMissingArtifactDescriptor() {
+ return getSession().isIgnoreMissingArtifactDescriptor();
+ }
+
+ public boolean isNotFoundCachingEnabled() {
+ return getSession().isNotFoundCachingEnabled();
+ }
+
+ public boolean isOffline() {
+ return getSession().isOffline();
+ }
+
+ public boolean isTransferErrorCachingEnabled() {
+ return getSession().isTransferErrorCachingEnabled();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/DefaultMavenComponentContributor.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/DefaultMavenComponentContributor.java
new file mode 100644
index 00000000..038d1452
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/DefaultMavenComponentContributor.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import org.apache.maven.classrealm.ClassRealmManagerDelegate;
+import org.apache.maven.plugin.internal.PluginDependenciesResolver;
+import org.apache.maven.project.artifact.MavenMetadataCache;
+
+import org.sonatype.aether.impl.LocalRepositoryMaintainer;
+import org.sonatype.plexus.build.incremental.BuildContext;
+
+import org.eclipse.m2e.core.internal.project.EclipseMavenMetadataCache;
+import org.eclipse.m2e.core.internal.project.registry.EclipsePluginDependenciesResolver;
+
+
+/**
+ */
+public class DefaultMavenComponentContributor implements IMavenComponentContributor {
+
+ public void contribute(IMavenComponentBinder binder) {
+ binder.bind(MavenMetadataCache.class, EclipseMavenMetadataCache.class, null);
+ binder.bind(PluginDependenciesResolver.class, EclipsePluginDependenciesResolver.class, null);
+ binder.bind(BuildContext.class, EclipseBuildContext.class, null);
+ binder.bind(ClassRealmManagerDelegate.class, EclipseClassRealmManagerDelegate.class, EclipseClassRealmManagerDelegate.ROLE_HINT);
+ binder.bind(LocalRepositoryMaintainer.class, EclipseLocalRepositoryMaintainer.class, EclipseLocalRepositoryMaintainer.ROLE_HINT);
+ binder.bind(ContextRepositorySystemSession.class, ContextRepositorySystemSessionImpl.class, null);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseBuildContext.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseBuildContext.java
new file mode 100644
index 00000000..52cfc528
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseBuildContext.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import org.codehaus.plexus.component.annotations.Component;
+
+import org.sonatype.plexus.build.incremental.BuildContext;
+import org.sonatype.plexus.build.incremental.ThreadBuildContext;
+
+
+/**
+ * Incremental build context.
+ */
+@Component(role = BuildContext.class)
+public class EclipseBuildContext extends ThreadBuildContext {
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseClassRealmManagerDelegate.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseClassRealmManagerDelegate.java
new file mode 100644
index 00000000..b623d1ec
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseClassRealmManagerDelegate.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
+import org.apache.maven.classrealm.ClassRealmConstituent;
+import org.apache.maven.classrealm.ClassRealmManagerDelegate;
+import org.apache.maven.classrealm.ClassRealmRequest;
+
+
+/**
+ * EclipseArtifactFilterManager
+ *
+ * @author igor
+ */
+@Component(role = ClassRealmManagerDelegate.class)
+public class EclipseClassRealmManagerDelegate implements ClassRealmManagerDelegate {
+
+ public static final String ROLE_HINT = EclipseClassRealmManagerDelegate.class.getName();
+
+ @Requirement
+ private PlexusContainer plexus;
+
+ private final ArtifactVersion currentBuildApiVersion;
+
+ public EclipseClassRealmManagerDelegate() {
+ Properties props = new Properties();
+ InputStream is = getClass().getResourceAsStream("/org/sonatype/plexus/build/incremental/version.properties"); //$NON-NLS-1$
+ if(is != null) {
+ try {
+ props.load(is);
+ } catch(IOException e) {
+ e.printStackTrace();
+ }
+ }
+ currentBuildApiVersion = new DefaultArtifactVersion(props.getProperty("api.version", "0.0.5")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public void setupRealm(ClassRealm realm, ClassRealmRequest request) {
+ if(supportsBuildApi(request.getConstituents())) {
+ ClassRealm coreRealm = plexus.getContainerRealm();
+
+ realm.importFrom(coreRealm, "org.codehaus.plexus.util.AbstractScanner"); //$NON-NLS-1$
+ realm.importFrom(coreRealm, "org.codehaus.plexus.util.Scanner"); //$NON-NLS-1$
+
+ realm.importFrom(coreRealm, "org.sonatype.plexus.build.incremental"); //$NON-NLS-1$
+ }
+ }
+
+ private boolean supportsBuildApi(List<ClassRealmConstituent> constituents) {
+ for(Iterator<ClassRealmConstituent> it = constituents.iterator(); it.hasNext();) {
+ ClassRealmConstituent constituent = it.next();
+ if("org.sonatype.plexus".equals(constituent.getGroupId()) //$NON-NLS-1$
+ && "plexus-build-api".equals(constituent.getArtifactId())) { //$NON-NLS-1$
+ ArtifactVersion version = new DefaultArtifactVersion(constituent.getVersion());
+ boolean compatible = currentBuildApiVersion.compareTo(version) >= 0;
+ if(compatible) {
+ // removing the JAR from the plugin realm to prevent discovery of the DefaultBuildContext
+ it.remove();
+ }
+ return compatible;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLocalRepositoryMaintainer.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLocalRepositoryMaintainer.java
new file mode 100644
index 00000000..77ce63c7
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLocalRepositoryMaintainer.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import java.io.File;
+
+import org.codehaus.plexus.component.annotations.Component;
+
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.impl.LocalRepositoryEvent;
+import org.sonatype.aether.impl.LocalRepositoryMaintainer;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.ILocalRepositoryListener;
+
+/**
+ * EclipseLocalRepositoryMaintainer
+ *
+ * @author igor
+ */
+@Component(role = LocalRepositoryMaintainer.class)
+public class EclipseLocalRepositoryMaintainer implements LocalRepositoryMaintainer {
+
+ public static final String ROLE_HINT = EclipseLocalRepositoryMaintainer.class.getName();
+
+ public void artifactDownloaded(LocalRepositoryEvent event) {
+ notifyListeners(event);
+ }
+
+ public void artifactInstalled(LocalRepositoryEvent event) {
+ notifyListeners(event);
+ }
+
+ private void notifyListeners(LocalRepositoryEvent event) {
+ MavenImpl maven = (MavenImpl) MavenPlugin.getDefault().getMaven();
+
+ File basedir = event.getRepository().getBasedir();
+ Artifact artifact = event.getArtifact();
+ ArtifactKey key = new ArtifactKey(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(),
+ artifact.getClassifier());
+ for(ILocalRepositoryListener listener : maven.getLocalRepositoryListeners()) {
+ listener.artifactInstalled(basedir, key, event.getFile());
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLogger.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLogger.java
new file mode 100644
index 00000000..16cbe8b6
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLogger.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import org.eclipse.osgi.util.NLS;
+
+import org.codehaus.plexus.logging.Logger;
+
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.internal.Messages;
+
+class EclipseLogger implements Logger {
+ private MavenConsole console;
+ private final IMavenConfiguration mavenConfiguration;
+
+ public EclipseLogger(MavenConsole console, IMavenConfiguration mavenConfiguration) {
+ this.console = console;
+ this.mavenConfiguration = mavenConfiguration;
+ }
+
+ private void out(String s) {
+ console.logMessage(s);
+ }
+
+ private void outError(String s) {
+ console.logError(s);
+ }
+
+ public void debug( String msg ) {
+ if (isDebugEnabled()) {
+ out(NLS.bind(Messages.EclipseLogger_debug1,msg));
+ }
+ }
+
+ public void debug( String msg, Throwable t) {
+ if (isDebugEnabled()) {
+ out( NLS.bind(Messages.EclipseLogger_debug2, msg, t.getMessage()));
+ }
+ }
+
+ public void info( String msg ) {
+ if (isInfoEnabled()) {
+ out( NLS.bind(Messages.EclipseLogger_info1, msg));
+ }
+ }
+
+ public void info( String msg, Throwable t ) {
+ if (isInfoEnabled()) {
+ out( NLS.bind(Messages.EclipseLogger_info2, msg, t.getMessage()));
+ }
+ }
+
+ public void warn( String msg ) {
+ if (isWarnEnabled()) {
+ out(NLS.bind(Messages.EclipseLogger_warn1, msg));
+ }
+ }
+
+ public void warn( String msg, Throwable t ) {
+ if (isWarnEnabled()) {
+ out( NLS.bind(Messages.EclipseLogger_warn2, msg, t.getMessage()));
+ }
+ }
+
+ public void fatalError( String msg ) {
+ if (isFatalErrorEnabled()) {
+ outError(NLS.bind(Messages.EclipseLogger_fatal1, msg));
+ }
+ }
+
+ public void fatalError( String msg, Throwable t ) {
+ if (isFatalErrorEnabled()) {
+ outError( NLS.bind(Messages.EclipseLogger_fatal2, msg, t.getMessage()));
+ }
+ }
+
+ public void error( String msg ) {
+ if (isErrorEnabled()) {
+ outError(NLS.bind(Messages.EclipseLogger_error1, msg));
+ }
+ }
+
+ public void error( String msg, Throwable t ) {
+ if (isErrorEnabled()) {
+ outError( NLS.bind(Messages.EclipseLogger_error2, msg, t.getMessage()));
+ }
+ }
+
+ public boolean isDebugEnabled() {
+ return mavenConfiguration.isDebugOutput();
+ }
+
+ public boolean isInfoEnabled() {
+ return true;
+ }
+
+ public boolean isWarnEnabled() {
+ return true;
+ }
+
+ public boolean isErrorEnabled() {
+ return true;
+ }
+
+ public boolean isFatalErrorEnabled() {
+ return true;
+ }
+
+ public void setThreshold( int treshold ) {
+ }
+
+ public int getThreshold() {
+ return LEVEL_DEBUG;
+ }
+
+ public Logger getChildLogger(String name) {
+ return this;
+ }
+
+ public String getName() {
+ return Messages.EclipseLogger_name;
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLoggerManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLoggerManager.java
new file mode 100644
index 00000000..2e6c4dd4
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/EclipseLoggerManager.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import org.codehaus.plexus.logging.AbstractLoggerManager;
+import org.codehaus.plexus.logging.Logger;
+
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+
+
+/**
+ * EclipseLoggerManager
+ *
+ * @author igor
+ */
+public class EclipseLoggerManager extends AbstractLoggerManager {
+
+ private EclipseLogger logger;
+
+ public EclipseLoggerManager(MavenConsole console, IMavenConfiguration mavenConfiguration) {
+ this.logger = new EclipseLogger(console, mavenConfiguration);
+ }
+
+ public int getActiveLoggerCount() {
+ return 1;
+ }
+
+ public Logger getLoggerForComponent(String arg0, String arg1) {
+ return logger;
+ }
+
+ public int getThreshold() {
+ return Logger.LEVEL_DEBUG;
+ }
+
+ public int getThreshold(String arg0, String arg1) {
+ return Logger.LEVEL_DEBUG;
+ }
+
+ public void returnComponentLogger(String arg0, String arg1) {
+ }
+
+ public void setThreshold(int arg0) {
+ }
+
+ public void setThreshold(String arg0, String arg1, int arg2) {
+ }
+
+ public void setThresholds(int arg0) {
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ExtensionModule.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ExtensionModule.java
new file mode 100644
index 00000000..ddf309c1
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/ExtensionModule.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.name.Names;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+
+
+/**
+ * A custom Guice module that picks the components contributed by extensions.
+ */
+class ExtensionModule extends AbstractModule implements IMavenComponentContributor.IMavenComponentBinder {
+
+ public <T> void bind(Class<T> role, Class<? extends T> impl, String hint) {
+ if(hint == null || hint.length() <= 0 || "default".equals(hint)) { //$NON-NLS-1$
+ bind(role).to(impl);
+ } else {
+ bind(role).annotatedWith(Names.named(hint)).to(impl);
+ }
+ }
+
+ protected void configure() {
+ IExtensionRegistry r = Platform.getExtensionRegistry();
+ for(IConfigurationElement c : r.getConfigurationElementsFor(IMavenConstants.MAVEN_COMPONENT_CONTRIBUTORS_XPT)) {
+ if("configurator".equals(c.getName())) { //$NON-NLS-1$
+ try {
+ IMavenComponentContributor contributor = (IMavenComponentContributor) c.createExecutableExtension("class"); //$NON-NLS-1$
+ contributor.contribute(this);
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/IMavenComponentContributor.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/IMavenComponentContributor.java
new file mode 100644
index 00000000..fd4963cc
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/IMavenComponentContributor.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+/**
+ * Allows extensions to contribute components to the Maven core container.
+ */
+public interface IMavenComponentContributor {
+
+ void contribute(IMavenComponentBinder binder);
+
+ public interface IMavenComponentBinder {
+
+ <T> void bind(Class<T> role, Class<? extends T> impl, String hint);
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenConfigurationImpl.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenConfigurationImpl.java
new file mode 100644
index 00000000..fd786884
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenConfigurationImpl.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.embedder.IMavenConfigurationChangeListener;
+import org.eclipse.m2e.core.embedder.MavenConfigurationChangeEvent;
+import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
+
+
+public class MavenConfigurationImpl implements IMavenConfiguration, IPropertyChangeListener {
+
+ private final IPreferenceStore preferenceStore;
+ private final ListenerList listeners = new ListenerList(ListenerList.IDENTITY);
+
+ public MavenConfigurationImpl(IPreferenceStore preferenceStore) {
+ this.preferenceStore = preferenceStore;
+ preferenceStore.addPropertyChangeListener(this);
+ }
+
+ public String getGlobalSettingsFile() {
+ return preferenceStore.getString(MavenPreferenceConstants.P_GLOBAL_SETTINGS_FILE);
+ }
+
+ public String getJiraPassword() {
+ return preferenceStore.getString(MavenPreferenceConstants.P_JIRA_PASSWORD);
+ }
+
+ public String getJiraUsername() {
+ return preferenceStore.getString(MavenPreferenceConstants.P_JIRA_USERNAME);
+ }
+
+ public String getUserSettingsFile() {
+ return preferenceStore.getString(MavenPreferenceConstants.P_USER_SETTINGS_FILE);
+ }
+
+ public boolean isDebugOutput() {
+ return preferenceStore.getBoolean(MavenPreferenceConstants.P_DEBUG_OUTPUT);
+ }
+
+ public boolean isDownloadJavaDoc() {
+ return preferenceStore.getBoolean(MavenPreferenceConstants.P_DOWNLOAD_JAVADOC);
+ }
+
+ public boolean isDownloadSources() {
+ return preferenceStore.getBoolean(MavenPreferenceConstants.P_DOWNLOAD_SOURCES);
+ }
+
+ public boolean isHideFoldersOfNestedProjects() {
+ return preferenceStore.getBoolean(MavenPreferenceConstants.P_HIDE_FOLDERS_OF_NESTED_PROJECTS);
+ }
+
+ public boolean isOffline() {
+ return preferenceStore.getBoolean(MavenPreferenceConstants.P_OFFLINE);
+ }
+
+ public void setUserSettingsFile(String settingsFile) {
+ preferenceStore.setValue(MavenPreferenceConstants.P_USER_SETTINGS_FILE, nvl(settingsFile));
+ }
+
+ public void setGlobalSettingsFile(String globalSettingsFile){
+ preferenceStore.setValue(MavenPreferenceConstants.P_GLOBAL_SETTINGS_FILE, nvl(globalSettingsFile));
+ }
+
+ private static String nvl(String s) {
+ return s == null ? "" : s; //$NON-NLS-1$
+ }
+
+ public boolean isUpdateProjectsOnStartup() {
+ return preferenceStore.getBoolean(MavenPreferenceConstants.P_UPDATE_PROJECTS);
+ }
+
+ public boolean isUpdateIndexesOnStartup() {
+ return preferenceStore.getBoolean(MavenPreferenceConstants.P_UPDATE_INDEXES);
+ }
+
+ public synchronized void addConfigurationChangeListener(IMavenConfigurationChangeListener listener) {
+ this.listeners.add(listener);
+ }
+
+ public void propertyChange(PropertyChangeEvent event) {
+ MavenConfigurationChangeEvent mavenEvent = new MavenConfigurationChangeEvent(event.getProperty(), event.getNewValue(), event.getOldValue());
+ for (Object listener : listeners.getListeners()) {
+ try {
+ ((IMavenConfigurationChangeListener) listener).mavenConfigutationChange(mavenEvent);
+ } catch (Exception e) {
+ MavenLogger.log("Could not deliver maven configuration change event", e);
+ }
+ }
+
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenEmbeddedRuntime.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenEmbeddedRuntime.java
new file mode 100644
index 00000000..e9142b62
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenEmbeddedRuntime.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMavenLauncherConfiguration;
+import org.eclipse.m2e.core.embedder.MavenRuntime;
+import org.eclipse.m2e.core.embedder.MavenRuntimeManager;
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * Embedded Maven runtime
+ *
+ * @author Eugene Kuleshov
+ * @author Igor Fedorenko
+ */
+public class MavenEmbeddedRuntime implements MavenRuntime {
+
+ private static final String MAVEN_MAVEN_EMBEDDER_BUNDLE_ID = "org.eclipse.m2e.maven.runtime"; //$NON-NLS-1$
+
+ private static final String MAVEN_EXECUTOR_CLASS = org.apache.maven.cli.MavenCli.class.getName();
+
+ public static final String PLEXUS_CLASSWORLD_NAME = "plexus.core"; //$NON-NLS-1$
+
+ private static String[] LAUNCHER_CLASSPATH;
+ private static String[] CLASSPATH;
+
+ private static volatile String mavenVersion;
+
+ private BundleContext bundleContext;
+
+ public MavenEmbeddedRuntime(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ public boolean isEditable() {
+ return false;
+ }
+
+ public String getLocation() {
+ return MavenRuntimeManager.EMBEDDED;
+ }
+
+ public String getSettings() {
+ return null;
+ }
+
+ public boolean isAvailable() {
+ return true;
+ }
+
+ public void createLauncherConfiguration(IMavenLauncherConfiguration collector, IProgressMonitor monitor) throws CoreException {
+ collector.setMainType(MAVEN_EXECUTOR_CLASS, PLEXUS_CLASSWORLD_NAME);
+
+ initClasspath(findMavenEmbedderBundle());
+
+ collector.addRealm(IMavenLauncherConfiguration.LAUNCHER_REALM);
+ for(String entry : LAUNCHER_CLASSPATH) {
+ collector.addArchiveEntry(entry);
+ }
+
+ collector.addRealm(PLEXUS_CLASSWORLD_NAME);
+ for(String entry : CLASSPATH) {
+ // https://issues.sonatype.org/browse/MNGECLIPSE-2507
+ if(!entry.contains("plexus-build-api")) {
+ collector.addArchiveEntry(entry);
+ }
+ }
+ }
+
+ private static synchronized void initClasspath(Bundle bundle) {
+ if(CLASSPATH == null) {
+ List<String> cp = new ArrayList<String>();
+ List<String> lcp = new ArrayList<String>();
+
+ @SuppressWarnings("unchecked")
+ Enumeration<URL> entries = bundle.findEntries("/", "*", true); //$NON-NLS-1$ //$NON-NLS-2$
+ while(entries.hasMoreElements()) {
+ URL url = entries.nextElement();
+ String path = url.getPath();
+ if(path.endsWith(".jar") || path.endsWith("bin/")) { //$NON-NLS-1$ //$NON-NLS-2$
+ try {
+ String file = FileLocator.toFileURL(url).getFile();
+ if (file.contains("plexus-classworlds")) { //$NON-NLS-1$
+ lcp.add(file);
+ } else {
+ cp.add(file);
+ }
+ } catch(IOException ex) {
+ MavenLogger.log("Error adding classpath entry " + url.toString(), ex);
+ }
+ }
+ }
+
+ CLASSPATH = cp.toArray(new String[cp.size()]);
+ LAUNCHER_CLASSPATH = lcp.toArray(new String[lcp.size()]);
+ }
+ }
+
+ private Bundle findMavenEmbedderBundle() {
+ Bundle bundle = null;
+ Bundle[] bundles = bundleContext.getBundles();
+ for(int i = 0; i < bundles.length; i++ ) {
+ if(MAVEN_MAVEN_EMBEDDER_BUNDLE_ID.equals(bundles[i].getSymbolicName())) {
+ bundle = bundles[i];
+ break;
+ }
+ }
+ return bundle;
+ }
+
+ public String toString() {
+ Bundle embedder = Platform.getBundle(MAVEN_MAVEN_EMBEDDER_BUNDLE_ID);
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("Embedded (").append(getVersion()); //$NON-NLS-1$
+ if (embedder != null) {
+ String version = (String) embedder.getHeaders().get(Constants.BUNDLE_VERSION);
+ sb.append('/').append(version);
+ }
+ sb.append(')');
+
+ return sb.toString();
+ }
+
+ private static synchronized String getVersion(Bundle bundle) {
+ if(mavenVersion != null) {
+ return mavenVersion;
+ }
+ initClasspath(bundle);
+ try {
+ String mavenCoreJarPath = null;
+ for(String path : CLASSPATH) {
+ if(path.contains("maven-core") && path.endsWith(".jar")) {
+ mavenCoreJarPath = path;
+ break;
+ }
+ }
+
+ if(mavenCoreJarPath == null) {
+ throw new RuntimeException("Could not find maven core jar file");
+ }
+
+ ZipFile zip = new ZipFile(mavenCoreJarPath);
+ try {
+ ZipEntry zipEntry = zip.getEntry("META-INF/maven/org.apache.maven/maven-core/pom.properties"); //$NON-NLS-1$
+ if(zipEntry != null) {
+ Properties pomProperties = new Properties();
+ pomProperties.load(zip.getInputStream(zipEntry));
+
+ String version = pomProperties.getProperty("version"); //$NON-NLS-1$
+ if(version != null) {
+ mavenVersion = version;
+ return mavenVersion;
+ }
+ }
+ } finally {
+ zip.close();
+ }
+ } catch(Exception e) {
+ MavenLogger.log("Could not determine embedded maven version", e);
+ }
+
+ return Messages.MavenEmbeddedRuntime_unknown;
+ }
+
+ public String getVersion() {
+ Bundle bundle = findMavenEmbedderBundle();
+ return getVersion(bundle);
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenExternalRuntime.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenExternalRuntime.java
new file mode 100644
index 00000000..e11f84b1
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenExternalRuntime.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.URL;
+import java.util.Properties;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.codehaus.plexus.classworlds.launcher.ConfigurationHandler;
+import org.codehaus.plexus.classworlds.launcher.ConfigurationParser;
+import org.codehaus.plexus.util.DirectoryScanner;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMavenLauncherConfiguration;
+import org.eclipse.m2e.core.embedder.MavenRuntime;
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * Maven external runtime using ClassWorlds launcher
+ *
+ * @author Eugene Kuleshov
+ * @author Igor Fedorenko
+ *
+ */
+public class MavenExternalRuntime implements MavenRuntime {
+
+ private static final String PROPERTY_MAVEN_HOME = "maven.home"; //$NON-NLS-1$
+
+ private final String location;
+
+
+ public MavenExternalRuntime(String location) {
+ this.location = location;
+ }
+
+ public boolean isEditable() {
+ return true;
+ }
+
+ public boolean isAvailable() {
+ return new File(location, "bin").exists() && getLauncherClasspath() != null; //$NON-NLS-1$
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ public String getSettings() {
+ return location + File.separator + "conf" + File.separator + "settings.xml"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public String getMainTypeName() {
+ return "org.codehaus.classworlds.Launcher"; //$NON-NLS-1$
+ }
+
+ private File getLauncherConfigurationFile() {
+ return new File(location, "bin/m2.conf"); //$NON-NLS-1$
+ }
+
+ public void createLauncherConfiguration(final IMavenLauncherConfiguration collector, IProgressMonitor monitor) throws CoreException {
+
+ collector.addRealm(IMavenLauncherConfiguration.LAUNCHER_REALM);
+ collector.addArchiveEntry(getLauncherClasspath());
+
+ ConfigurationHandler handler = new ConfigurationHandler() {
+ public void addImportFrom(String relamName, String importSpec) {
+ throw new UnsupportedOperationException(Messages.MavenExternalRuntime_exc_unsupported);
+ }
+ public void addLoadFile(File file) {
+ try {
+ collector.addArchiveEntry(file.getAbsolutePath());
+ } catch(CoreException ex) {
+ throw new ExceptionWrapper(ex);
+ }
+ }
+ public void addLoadURL(URL url) {
+ try {
+ collector.addArchiveEntry(url.toExternalForm());
+ } catch(CoreException ex) {
+ throw new ExceptionWrapper(ex);
+ }
+ }
+ public void addRealm(String realmName) {
+ collector.addRealm(realmName);
+ }
+ public void setAppMain(String mainClassName, String mainRealmName) {
+ collector.setMainType(mainClassName, mainRealmName);
+ }
+ };
+
+ Properties properties = new Properties();
+ properties.put(PROPERTY_MAVEN_HOME, location);
+
+ ConfigurationParser parser = new ConfigurationParser(handler, properties);
+
+ try {
+ FileInputStream is = new FileInputStream(getLauncherConfigurationFile());
+ try {
+ parser.parse(is);
+ } finally {
+ is.close();
+ }
+ } catch (Exception e) {
+ if (e instanceof ExceptionWrapper && e.getCause() instanceof CoreException) {
+ throw (CoreException) e.getCause();
+ }
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenExternalRuntime_error_cannot_parse, e));
+ }
+
+ // XXX show error dialog and fail launch
+ }
+
+ public boolean equals(Object o) {
+ if(o instanceof MavenExternalRuntime) {
+ return location.equals(((MavenExternalRuntime) o).location);
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return location.hashCode();
+ }
+
+ public String toString() {
+ return "External" + " " + location + " (" + getVersion() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+
+ private static class ExceptionWrapper extends RuntimeException {
+ private static final long serialVersionUID = 8815818826909815028L;
+ public ExceptionWrapper(Exception cause) {
+ super(cause);
+ }
+ }
+
+ private String getLauncherClasspath() {
+ File mavenHome = new File(location);
+ DirectoryScanner ds = new DirectoryScanner();
+ ds.setBasedir(mavenHome);
+ ds.setIncludes(new String[] {
+ "core/boot/classworlds*.jar", // 2.0.4 //$NON-NLS-1$
+ "boot/classworlds*.jar", // 2.0.7 //$NON-NLS-1$
+ "boot/plexus-classworlds*.jar", // 2.1 as of 2008-03-27 //$NON-NLS-1$
+ });
+ ds.scan();
+ String[] includedFiles = ds.getIncludedFiles();
+
+ if (includedFiles.length == 1) {
+ return new File(mavenHome, includedFiles[0]).getAbsolutePath();
+ }
+
+ return null;
+ }
+
+ public String getVersion() {
+
+ class VersionHandler implements ConfigurationHandler {
+ File mavenCore;
+ File uber;
+ public void addImportFrom(String relamName, String importSpec) {
+ }
+ public void addLoadFile(File file) {
+ if (file.getName().contains("maven-core")) { //$NON-NLS-1$
+ mavenCore = file;
+ } else if (file.getName().endsWith("uber.jar")) { //$NON-NLS-1$
+ uber = file;
+ }
+ }
+ public void addLoadURL(URL url) {
+ }
+ public void addRealm(String realmName) {
+ }
+ public void setAppMain(String mainClassName, String mainRealmName) {
+ }
+ };
+ VersionHandler handler = new VersionHandler();
+
+ Properties properties = new Properties();
+ properties.put(PROPERTY_MAVEN_HOME, location);
+
+ ConfigurationParser parser = new ConfigurationParser(handler, properties);
+
+ try {
+ FileInputStream is = new FileInputStream(getLauncherConfigurationFile());
+ try {
+ parser.parse(is);
+ } finally {
+ is.close();
+ }
+
+ ZipFile zip = null;
+ if (handler.mavenCore != null) {
+ zip = new ZipFile(handler.mavenCore);
+ } else if (handler.uber != null) {
+ zip = new ZipFile(handler.uber);
+ }
+ if (zip != null) {
+ try {
+ ZipEntry zipEntry = zip.getEntry("META-INF/maven/org.apache.maven/maven-core/pom.properties"); //$NON-NLS-1$
+ if (zipEntry != null) {
+ Properties pomProperties = new Properties();
+ pomProperties.load(zip.getInputStream(zipEntry));
+
+ String version = pomProperties.getProperty("version"); //$NON-NLS-1$
+ if (version != null) {
+ return version;
+ }
+ }
+ } finally {
+ zip.close();
+ }
+ }
+
+ } catch (Exception e) {
+ // most likely a bad location, but who knows
+ MavenLogger.log("Could not parse classwords configuration file", e);
+ }
+
+
+ return Messages.MavenExternalRuntime_unknown;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java
new file mode 100644
index 00000000..6d4fb2a4
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java
@@ -0,0 +1,1098 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+
+import org.codehaus.plexus.ContainerConfiguration;
+import org.codehaus.plexus.DefaultContainerConfiguration;
+import org.codehaus.plexus.DefaultPlexusContainer;
+import org.codehaus.plexus.MutablePlexusContainer;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.PlexusContainerException;
+import org.codehaus.plexus.classworlds.ClassWorld;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
+import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
+import org.codehaus.plexus.component.configurator.converters.ConfigurationConverter;
+import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
+import org.codehaus.plexus.component.configurator.converters.lookup.DefaultConverterLookup;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.dag.CycleDetectedException;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+import org.apache.maven.DefaultMaven;
+import org.apache.maven.Maven;
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.InvalidRepositoryException;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.execution.DefaultMavenExecutionRequest;
+import org.apache.maven.execution.DefaultMavenExecutionResult;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionRequestPopulationException;
+import org.apache.maven.execution.MavenExecutionRequestPopulator;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.LifecycleExecutor;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.model.ConfigurationContainer;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.Profile;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.io.ModelReader;
+import org.apache.maven.model.io.ModelWriter;
+import org.apache.maven.plugin.BuildPluginManager;
+import org.apache.maven.plugin.InvalidPluginDescriptorException;
+import org.apache.maven.plugin.MavenPluginManager;
+import org.apache.maven.plugin.Mojo;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.MojoNotFoundException;
+import org.apache.maven.plugin.PluginConfigurationException;
+import org.apache.maven.plugin.PluginContainerException;
+import org.apache.maven.plugin.PluginDescriptorParsingException;
+import org.apache.maven.plugin.PluginManagerException;
+import org.apache.maven.plugin.PluginNotFoundException;
+import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
+import org.apache.maven.plugin.PluginResolutionException;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
+import org.apache.maven.plugin.version.PluginVersionRequest;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.apache.maven.plugin.version.PluginVersionResolver;
+import org.apache.maven.project.DuplicateProjectException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingException;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.ProjectBuildingResult;
+import org.apache.maven.project.ProjectSorter;
+import org.apache.maven.repository.RepositorySystem;
+import org.apache.maven.repository.internal.MavenRepositorySystemSession;
+import org.apache.maven.settings.Mirror;
+import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Server;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.SettingsUtils;
+import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
+import org.apache.maven.settings.building.DefaultSettingsProblem;
+import org.apache.maven.settings.building.SettingsBuilder;
+import org.apache.maven.settings.building.SettingsBuildingException;
+import org.apache.maven.settings.building.SettingsBuildingRequest;
+import org.apache.maven.settings.building.SettingsProblem;
+import org.apache.maven.settings.building.SettingsProblem.Severity;
+import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
+import org.apache.maven.settings.crypto.SettingsDecrypter;
+import org.apache.maven.settings.crypto.SettingsDecryptionRequest;
+import org.apache.maven.settings.crypto.SettingsDecryptionResult;
+import org.apache.maven.settings.io.SettingsWriter;
+import org.apache.maven.wagon.proxy.ProxyInfo;
+
+import org.sonatype.aether.RepositorySystemSession;
+import org.sonatype.aether.repository.LocalRepository;
+import org.sonatype.aether.resolution.ArtifactRequest;
+import org.sonatype.aether.resolution.ArtifactResolutionException;
+import org.sonatype.aether.resolution.ArtifactResult;
+import org.sonatype.aether.transfer.ArtifactNotFoundException;
+import org.sonatype.aether.transfer.TransferListener;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ILocalRepositoryListener;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.embedder.IMavenConfigurationChangeListener;
+import org.eclipse.m2e.core.embedder.ISettingsChangeListener;
+import org.eclipse.m2e.core.embedder.MavenConfigurationChangeEvent;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
+
+
+public class MavenImpl implements IMaven, IMavenConfigurationChangeListener {
+
+ /**
+ * Id of maven core class realm
+ */
+ public static final String MAVEN_CORE_REALM_ID = "plexus.core"; //$NON-NLS-1$
+
+
+ private DefaultPlexusContainer plexus;
+
+ private final IMavenConfiguration mavenConfiguration;
+
+ private final ConverterLookup converterLookup = new DefaultConverterLookup();
+
+ private final MavenConsole console;
+
+ private final ArrayList<ISettingsChangeListener> settingsListeners = new ArrayList<ISettingsChangeListener>();
+
+ private final ArrayList<ILocalRepositoryListener> localRepositoryListeners = new ArrayList<ILocalRepositoryListener>();
+
+ public MavenImpl(IMavenConfiguration mavenConfiguration, MavenConsole console) {
+ this.console = console;
+ this.mavenConfiguration = mavenConfiguration;
+ mavenConfiguration.addConfigurationChangeListener(this);
+ }
+
+ public MavenExecutionRequest createExecutionRequest(IProgressMonitor monitor) throws CoreException {
+ MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+ if(mavenConfiguration.getGlobalSettingsFile() != null) {
+ request.setGlobalSettingsFile(new File(mavenConfiguration.getGlobalSettingsFile()));
+ }
+ if(mavenConfiguration.getUserSettingsFile() != null) {
+ request.setUserSettingsFile(new File(mavenConfiguration.getUserSettingsFile()));
+ }
+
+ try {
+ lookup(MavenExecutionRequestPopulator.class).populateFromSettings(request, getSettings());
+ } catch(MavenExecutionRequestPopulationException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_no_exec_req, ex));
+ }
+
+ ArtifactRepository localRepository = getLocalRepository();
+ request.setLocalRepository(localRepository);
+ request.setLocalRepositoryPath(localRepository.getBasedir());
+ request.setOffline(mavenConfiguration.isOffline());
+
+ // logging
+ request.setTransferListener(createArtifactTransferListener(monitor));
+
+ request.getUserProperties().put("m2e.version", MavenPlugin.getVersion()); //$NON-NLS-1$
+
+ request.setCacheNotFound(true);
+ request.setCacheTransferError(true);
+
+ // the right way to disable snapshot update
+ // request.setUpdateSnapshots(false);
+ return request;
+ }
+
+ public String getLocalRepositoryPath() {
+ String path = null;
+ try {
+ Settings settings = getSettings();
+ path = settings.getLocalRepository();
+ } catch(CoreException ex) {
+ // fall through
+ }
+ if(path == null) {
+ path = RepositorySystem.defaultUserLocalRepository.getAbsolutePath();
+ }
+ return path;
+ }
+
+ public MavenExecutionResult execute(MavenExecutionRequest request, IProgressMonitor monitor) {
+ // XXX is there a way to set per-request log level?
+
+ MavenExecutionResult result;
+ try {
+ lookup(MavenExecutionRequestPopulator.class).populateDefaults(request);
+ result = lookup(Maven.class).execute(request);
+ } catch(MavenExecutionRequestPopulationException ex) {
+ result = new DefaultMavenExecutionResult();
+ result.addException(ex);
+ } catch(Exception e) {
+ result = new DefaultMavenExecutionResult();
+ result.addException(e);
+ }
+ return result;
+ }
+
+ public MavenSession createSession(MavenExecutionRequest request, MavenProject project) {
+ RepositorySystemSession repoSession = createRepositorySession(request);
+ MavenExecutionResult result = new DefaultMavenExecutionResult();
+ MavenSession mavenSession = new MavenSession(plexus, repoSession, request, result);
+ if(project != null) {
+ mavenSession.setProjects(Collections.singletonList(project));
+ }
+ return mavenSession;
+ }
+
+ private RepositorySystemSession createRepositorySession(MavenExecutionRequest request) {
+ try {
+ return ((DefaultMaven) lookup(Maven.class)).newRepositorySession(request);
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ throw new IllegalStateException("Could not look up Maven embedder", ex);
+ }
+ }
+
+ public void execute(MavenSession session, MojoExecution execution, IProgressMonitor monitor) {
+ try {
+ lookup(BuildPluginManager.class).executeMojo(session, execution);
+ } catch(Exception ex) {
+ session.getResult().addException(ex);
+ }
+ }
+
+ public <T> T getConfiguredMojo(MavenSession session, MojoExecution mojoExecution, Class<T> clazz)
+ throws CoreException {
+ try {
+ MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+ // getPluginRealm creates plugin realm and populates pluginDescriptor.classRealm field
+ lookup(BuildPluginManager.class).getPluginRealm(session, mojoDescriptor.getPluginDescriptor());
+ return clazz.cast(lookup(MavenPluginManager.class).getConfiguredMojo(Mojo.class, session, mojoExecution));
+ } catch(PluginContainerException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ NLS.bind(Messages.MavenImpl_error_mojo, mojoExecution), ex));
+ } catch(PluginConfigurationException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ NLS.bind(Messages.MavenImpl_error_mojo, mojoExecution), ex));
+ } catch(ClassCastException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ NLS.bind(Messages.MavenImpl_error_mojo, mojoExecution), ex));
+ } catch(PluginResolutionException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ NLS.bind(Messages.MavenImpl_error_mojo, mojoExecution), ex));
+ } catch(PluginManagerException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ NLS.bind(Messages.MavenImpl_error_mojo, mojoExecution), ex));
+ }
+ }
+
+ public void releaseMojo(Object mojo, MojoExecution mojoExecution) throws CoreException {
+ lookup(MavenPluginManager.class).releaseMojo(mojo, mojoExecution);
+ }
+
+ public MavenExecutionPlan calculateExecutionPlan(MavenExecutionRequest request, MavenProject project,
+ IProgressMonitor monitor) throws CoreException {
+ MavenSession session = createSession(request, project);
+ try {
+ List<String> goals = request.getGoals();
+ return lookup(LifecycleExecutor.class).calculateExecutionPlan(session, goals.toArray(new String[goals.size()]));
+ } catch(Exception ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_calc_build_plan, ex));
+ }
+ }
+
+ public ArtifactRepository getLocalRepository() throws CoreException {
+ try {
+ String localRepositoryPath = getLocalRepositoryPath();
+ if(localRepositoryPath != null) {
+ return lookup(RepositorySystem.class).createLocalRepository(new File(localRepositoryPath));
+ }
+ return lookup(RepositorySystem.class).createLocalRepository(RepositorySystem.defaultUserLocalRepository);
+ } catch(InvalidRepositoryException ex) {
+ // can't happen
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ public Settings getSettings() throws CoreException {
+ // MUST NOT use createRequest!
+
+ // TODO: Can't that delegate to buildSettings()?
+ SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
+ request.setSystemProperties(System.getProperties());
+ if(mavenConfiguration.getGlobalSettingsFile() != null) {
+ request.setGlobalSettingsFile(new File(mavenConfiguration.getGlobalSettingsFile()));
+ }
+ if(mavenConfiguration.getUserSettingsFile() != null) {
+ request.setUserSettingsFile(new File(mavenConfiguration.getUserSettingsFile()));
+ }
+ try {
+ return lookup(SettingsBuilder.class).build(request).getEffectiveSettings();
+ } catch(SettingsBuildingException ex) {
+ String msg = "Could not read settings.xml, assuming default values";
+ MavenPlugin.getDefault().getConsole().logError(msg);
+ MavenLogger.log(msg, ex);
+ /*
+ * NOTE: This method provides input for various other core functions, just bailing out would make m2e highly
+ * unusuable. Instead, we fail gracefully and just ignore the broken settings, using defaults.
+ */
+ return new Settings();
+ }
+ }
+
+ public Settings buildSettings(String globalSettings, String userSettings) throws CoreException {
+ SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
+ request.setGlobalSettingsFile(globalSettings != null ? new File(globalSettings) : null);
+ request.setUserSettingsFile(userSettings != null ? new File(userSettings) : null);
+ try {
+ return lookup(SettingsBuilder.class).build(request).getEffectiveSettings();
+ } catch(SettingsBuildingException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenImpl_error_read_settings,
+ ex));
+ }
+ }
+
+ public void writeSettings(Settings settings, OutputStream out) throws CoreException {
+ try {
+ lookup(SettingsWriter.class).write(out, null, settings);
+ } catch(IOException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenImpl_error_write_settings,
+ ex));
+ }
+ }
+
+ public List<SettingsProblem> validateSettings(String settings) {
+ List<SettingsProblem> problems = new ArrayList<SettingsProblem>();
+ if(settings != null) {
+ File settingsFile = new File(settings);
+ if(settingsFile.canRead()) {
+ SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
+ request.setUserSettingsFile(settingsFile);
+ try {
+ lookup(SettingsBuilder.class).build(request);
+ } catch(SettingsBuildingException ex) {
+ problems.addAll(ex.getProblems());
+ } catch(CoreException ex) {
+ problems.add(new DefaultSettingsProblem(ex.getMessage(), Severity.FATAL, settings, -1, -1, ex));
+ }
+ } else {
+ problems.add(new DefaultSettingsProblem(NLS.bind(Messages.MavenImpl_error_read_settings2, settings),
+ SettingsProblem.Severity.ERROR, settings, -1, -1, null));
+ }
+ }
+
+ return problems;
+ }
+
+ public void reloadSettings() throws CoreException {
+ // TODO do something more meaningful
+ Settings settings = getSettings();
+ for(ISettingsChangeListener listener : settingsListeners) {
+ try {
+ listener.settingsChanged(settings);
+ } catch(CoreException e) {
+ MavenLogger.log(e);
+ }
+ }
+ }
+
+ public Server decryptPassword(Server server) throws CoreException {
+ SettingsDecryptionRequest request = new DefaultSettingsDecryptionRequest(server);
+ SettingsDecryptionResult result = lookup(SettingsDecrypter.class).decrypt(request);
+ for(SettingsProblem problem : result.getProblems()) {
+ MavenLogger.log(new Status(IStatus.WARNING, IMavenConstants.PLUGIN_ID, -1, problem.getMessage(), problem
+ .getException()));
+ }
+ return result.getServer();
+ }
+
+ public void mavenConfigutationChange(MavenConfigurationChangeEvent event) throws CoreException {
+ if(MavenConfigurationChangeEvent.P_USER_SETTINGS_FILE.equals(event.getKey())
+ || MavenPreferenceConstants.P_GLOBAL_SETTINGS_FILE.equals(event.getKey())) {
+ reloadSettings();
+ }
+ }
+
+ public Model readModel(InputStream in) throws CoreException {
+ try {
+ return lookup(ModelReader.class).read(in, null);
+ } catch(IOException e) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenImpl_error_read_pom, e));
+ }
+ }
+
+ public Model readModel(File pomFile) throws CoreException {
+ try {
+ BufferedInputStream is = new BufferedInputStream(new FileInputStream(pomFile));
+ try {
+ return readModel(is);
+ } finally {
+ IOUtil.close(is);
+ }
+ } catch(IOException e) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenImpl_error_read_pom, e));
+ }
+ }
+
+ public void writeModel(Model model, OutputStream out) throws CoreException {
+ try {
+ lookup(ModelWriter.class).write(out, null, model);
+ } catch(IOException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenImpl_error_write_pom, ex));
+ }
+ }
+
+ public MavenProject readProject(File pomFile, IProgressMonitor monitor) throws CoreException {
+ try {
+ MavenExecutionRequest request = createExecutionRequest(monitor);
+ lookup(MavenExecutionRequestPopulator.class).populateDefaults(request);
+ ProjectBuildingRequest configuration = request.getProjectBuildingRequest();
+ configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+ configuration.setRepositorySession(createRepositorySession(request));
+ return lookup(ProjectBuilder.class).build(pomFile, configuration).getProject();
+ } catch(ProjectBuildingException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenImpl_error_read_project,
+ ex));
+ } catch(MavenExecutionRequestPopulationException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenImpl_error_read_project,
+ ex));
+ }
+ }
+
+ public MavenExecutionResult readProject(MavenExecutionRequest request, IProgressMonitor monitor) throws CoreException {
+ File pomFile = request.getPom();
+ MavenExecutionResult result = new DefaultMavenExecutionResult();
+ try {
+ lookup(MavenExecutionRequestPopulator.class).populateDefaults(request);
+ ProjectBuildingRequest configuration = request.getProjectBuildingRequest();
+ configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+ configuration.setRepositorySession(createRepositorySession(request));
+ ProjectBuildingResult projectBuildingResult = lookup(ProjectBuilder.class).build(pomFile, configuration);
+ result.setProject(projectBuildingResult.getProject());
+ result.setDependencyResolutionResult(projectBuildingResult.getDependencyResolutionResult());
+ } catch(ProjectBuildingException ex) {
+ //don't add the exception here. this should come out as a build marker, not fill
+ //the error logs with msgs
+ return result.addException(ex);
+ } catch(MavenExecutionRequestPopulationException ex) {
+ return result.addException(ex);
+ }
+ return result;
+ }
+
+ /**
+ * Makes MavenProject instances returned by #readProject methods suitable for caching and reuse with other
+ * MavenSession instances.<br/>
+ * Do note that MavenProject.getParentProject() cannot be used for detached MavenProject instances. Use
+ * #resolveParentProject to resolve parent project instance.
+ */
+ public void detachFromSession(MavenProject project) throws CoreException {
+ try {
+ // TODO remove reflection when we have embedder 3.0.1 or better
+ Field f = project.getClass().getDeclaredField("projectBuilderConfiguration"); //$NON-NLS-1$
+ f.setAccessible(true);
+ ProjectBuildingRequest request;
+ request = (ProjectBuildingRequest) f.get(project);
+ request.setRepositorySession(lookup(ContextRepositorySystemSession.class));
+ } catch(NoSuchFieldException ex) {
+ MavenLogger.log(ex.getMessage(), ex);
+ } catch(IllegalAccessException ex) {
+ MavenLogger.log(ex.getMessage(), ex);
+ }
+ }
+
+ public MavenProject resolveParentProject(MavenExecutionRequest request, MavenProject child, IProgressMonitor monitor)
+ throws CoreException {
+ ProjectBuildingRequest configuration = request.getProjectBuildingRequest();
+ configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+ configuration.setRepositorySession(createRepositorySession(request));
+
+ try {
+ configuration.setRemoteRepositories(child.getRemoteArtifactRepositories());
+
+ File parentFile = child.getParentFile();
+ if(parentFile != null) {
+ return lookup(ProjectBuilder.class).build(parentFile, configuration).getProject();
+ }
+
+ Artifact parentArtifact = child.getParentArtifact();
+ if(parentArtifact != null) {
+ return lookup(ProjectBuilder.class).build(parentArtifact, configuration).getProject();
+ }
+ } catch(ProjectBuildingException ex) {
+ MavenLogger.log("Could not read parent project", ex);
+ }
+
+ return null;
+ }
+
+ public Artifact resolve(String groupId, String artifactId, String version, String type, String classifier,
+ List<ArtifactRepository> remoteRepositories, IProgressMonitor monitor) throws CoreException {
+ Artifact artifact = lookup(RepositorySystem.class).createArtifactWithClassifier(groupId, artifactId, version, type,
+ classifier);
+
+ if(remoteRepositories == null) {
+ try {
+ remoteRepositories = getArtifactRepositories();
+ } catch(CoreException e) {
+ // we've tried
+ remoteRepositories = Collections.emptyList();
+ }
+ }
+
+ ArtifactRepository localRepository = getLocalRepository();
+
+ org.sonatype.aether.RepositorySystem repoSystem = lookup(org.sonatype.aether.RepositorySystem.class);
+
+ MavenRepositorySystemSession session = new MavenRepositorySystemSession();
+ session.setLocalRepositoryManager(repoSystem.newLocalRepositoryManager(new LocalRepository(localRepository
+ .getBasedir())));
+ session.setTransferListener(createArtifactTransferListener(monitor));
+
+ ArtifactRequest request = new ArtifactRequest();
+ request.setArtifact(RepositoryUtils.toArtifact(artifact));
+ request.setRepositories(RepositoryUtils.toRepos(remoteRepositories));
+
+ ArtifactResult result;
+ try {
+ result = repoSystem.resolveArtifact(session, request);
+ } catch(ArtifactResolutionException ex) {
+ result = ex.getResults().get(0);
+ }
+
+ setLastUpdated(localRepository, remoteRepositories, artifact);
+
+ if(result.isResolved()) {
+ artifact.selectVersion(result.getArtifact().getVersion());
+ artifact.setFile(result.getArtifact().getFile());
+ artifact.setResolved(true);
+ } else {
+ ArrayList<IStatus> members = new ArrayList<IStatus>();
+ for(Exception e : result.getExceptions()) {
+ if(!(e instanceof ArtifactNotFoundException)) {
+ members.add(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, e.getMessage(), e));
+ }
+ }
+ if(members.isEmpty()) {
+ members.add(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, NLS.bind(Messages.MavenImpl_error_missing, artifact), null));
+ }
+ IStatus[] newMembers = members.toArray(new IStatus[members.size()]);
+ throw new CoreException(new MultiStatus(IMavenConstants.PLUGIN_ID, -1, newMembers, Messages.MavenImpl_error_resolve,
+ null));
+ }
+
+ return artifact;
+ }
+
+ public String getArtifactPath(ArtifactRepository repository, String groupId, String artifactId, String version,
+ String type, String classifier) throws CoreException {
+ Artifact artifact = lookup(RepositorySystem.class).createArtifactWithClassifier(groupId, artifactId, version, type,
+ classifier);
+ return repository.pathOf(artifact);
+ }
+
+ private void setLastUpdated(ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories,
+ Artifact artifact) throws CoreException {
+
+ Properties lastUpdated = loadLastUpdated(localRepository, artifact);
+
+ String timestamp = Long.toString(System.currentTimeMillis());
+
+ for(ArtifactRepository repository : remoteRepositories) {
+ lastUpdated.setProperty(getLastUpdatedKey(repository, artifact), timestamp);
+ }
+
+ File lastUpdatedFile = getLastUpdatedFile(localRepository, artifact);
+ try {
+ lastUpdatedFile.getParentFile().mkdirs();
+ BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(lastUpdatedFile));
+ try {
+ lastUpdated.store(os, null);
+ } finally {
+ IOUtil.close(os);
+ }
+ } catch(IOException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_write_lastUpdated, ex));
+ }
+ }
+
+ /**
+ * This is a temporary implementation that only works for artifacts resolved using #resolve.
+ */
+ public boolean isUnavailable(String groupId, String artifactId, String version, String type, String classifier,
+ List<ArtifactRepository> remoteRepositories) throws CoreException {
+ Artifact artifact = lookup(RepositorySystem.class).createArtifactWithClassifier(groupId, artifactId, version, type,
+ classifier);
+
+ ArtifactRepository localRepository = getLocalRepository();
+
+ File artifactFile = new File(localRepository.getBasedir(), localRepository.pathOf(artifact));
+
+ if(artifactFile.canRead()) {
+ // artifact is available locally
+ return false;
+ }
+
+ if(remoteRepositories == null || remoteRepositories.isEmpty()) {
+ // no remote repositories
+ return true;
+ }
+
+ // now is the hard part
+ Properties lastUpdated = loadLastUpdated(localRepository, artifact);
+
+ for(ArtifactRepository repository : remoteRepositories) {
+ String timestamp = lastUpdated.getProperty(getLastUpdatedKey(repository, artifact));
+ if(timestamp == null) {
+ // availability of the artifact from this repository has not been checked yet
+ return false;
+ }
+ }
+
+ // artifact is not available locally and all remote repositories have been checked in the past
+ return true;
+ }
+
+ private String getLastUpdatedKey(ArtifactRepository repository, Artifact artifact) {
+ StringBuilder key = new StringBuilder();
+
+ // repository part
+ key.append(repository.getId());
+ if(repository.getAuthentication() != null) {
+ key.append('|').append(repository.getAuthentication().getUsername());
+ }
+ key.append('|').append(repository.getUrl());
+
+ // artifact part
+ key.append('|').append(artifact.getClassifier());
+
+ return key.toString();
+ }
+
+ private Properties loadLastUpdated(ArtifactRepository localRepository, Artifact artifact) throws CoreException {
+ Properties lastUpdated = new Properties();
+ File lastUpdatedFile = getLastUpdatedFile(localRepository, artifact);
+ try {
+ BufferedInputStream is = new BufferedInputStream(new FileInputStream(lastUpdatedFile));
+ try {
+ lastUpdated.load(is);
+ } finally {
+ IOUtil.close(is);
+ }
+ } catch(FileNotFoundException ex) {
+ // that's okay
+ } catch(IOException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_read_lastUpdated, ex));
+ }
+ return lastUpdated;
+ }
+
+ private File getLastUpdatedFile(ArtifactRepository localRepository, Artifact artifact) {
+ return new File(localRepository.getBasedir(), basePathOf(localRepository, artifact) + "/" //$NON-NLS-1$
+ + "m2e-lastUpdated.properties"); //$NON-NLS-1$
+ }
+
+ private static final char PATH_SEPARATOR = '/';
+
+ private static final char GROUP_SEPARATOR = '.';
+
+ private String basePathOf(ArtifactRepository repository, Artifact artifact) {
+ StringBuilder path = new StringBuilder(128);
+
+ path.append(formatAsDirectory(artifact.getGroupId())).append(PATH_SEPARATOR);
+ path.append(artifact.getArtifactId()).append(PATH_SEPARATOR);
+ path.append(artifact.getBaseVersion()).append(PATH_SEPARATOR);
+
+ return path.toString();
+ }
+
+ private String formatAsDirectory(String directory) {
+ return directory.replace(GROUP_SEPARATOR, PATH_SEPARATOR);
+ }
+
+ public <T> T getMojoParameterValue(MavenSession session, MojoExecution mojoExecution, String parameter,
+ Class<T> asType) throws CoreException {
+
+ try {
+ MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+
+ ClassRealm pluginRealm = lookup(BuildPluginManager.class).getPluginRealm(session,
+ mojoDescriptor.getPluginDescriptor());
+
+ ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator(session, mojoExecution);
+
+ ConfigurationConverter typeConverter = converterLookup.lookupConverterForType(asType);
+
+ Xpp3Dom dom = mojoExecution.getConfiguration();
+
+ if(dom == null) {
+ return null;
+ }
+
+ PlexusConfiguration pomConfiguration = new XmlPlexusConfiguration(dom);
+
+ PlexusConfiguration configuration = pomConfiguration.getChild(parameter);
+
+ if(configuration == null) {
+ return null;
+ }
+
+ Object value = typeConverter.fromConfiguration(converterLookup, configuration, asType,
+ mojoDescriptor.getImplementationClass(), pluginRealm, expressionEvaluator, null);
+ return asType.cast(value);
+ } catch(ComponentConfigurationException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_param, ex));
+ } catch(PluginManagerException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_param, ex));
+ } catch(PluginResolutionException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_param, ex));
+ }
+ }
+
+ public <T> T getMojoParameterValue(String parameter, Class<T> type, MavenSession session, Plugin plugin,
+ ConfigurationContainer configuration, String goal) throws CoreException {
+ Xpp3Dom config = (Xpp3Dom) configuration.getConfiguration();
+ config = (config != null) ? config.getChild(parameter) : null;
+
+ PlexusConfiguration paramConfig = null;
+
+ if(config == null) {
+ MojoDescriptor mojoDescriptor;
+
+ try {
+ mojoDescriptor = lookup(BuildPluginManager.class).getMojoDescriptor(plugin, goal,
+ session.getCurrentProject().getRemotePluginRepositories(), session.getRepositorySession());
+ } catch(PluginNotFoundException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_param, ex));
+ } catch(PluginResolutionException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_param, ex));
+ } catch(PluginDescriptorParsingException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_param, ex));
+ } catch(MojoNotFoundException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_param, ex));
+ } catch(InvalidPluginDescriptorException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_param, ex));
+ }
+
+ PlexusConfiguration defaultConfig = mojoDescriptor.getMojoConfiguration();
+ if(defaultConfig != null) {
+ paramConfig = defaultConfig.getChild(parameter, false);
+ }
+ } else {
+ paramConfig = new XmlPlexusConfiguration(config);
+ }
+
+ if(paramConfig == null) {
+ return null;
+ }
+
+ try {
+ MojoExecution mojoExecution = new MojoExecution(plugin, goal, "default"); //$NON-NLS-1$
+
+ ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator(session, mojoExecution);
+
+ ConfigurationConverter typeConverter = converterLookup.lookupConverterForType(type);
+
+ Object value = typeConverter.fromConfiguration(converterLookup, paramConfig, type, Object.class,
+ plexus.getContainerRealm(), expressionEvaluator, null);
+ return type.cast(value);
+ } catch(ComponentConfigurationException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_param, ex));
+ } catch(ClassCastException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_param, ex));
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void xxxRemoveExtensionsRealm(MavenProject project) {
+ ClassRealm realm = project.getClassRealm();
+ if(realm != null && realm != plexus.getContainerRealm()) {
+ ClassWorld world = ((MutablePlexusContainer) plexus).getClassWorld();
+ try {
+ world.disposeRealm(realm.getId());
+ } catch(NoSuchRealmException ex) {
+ MavenLogger.log("Could not dispose of project extensions class realm", ex);
+ }
+ }
+ }
+
+ public ArtifactRepository createArtifactRepository(String id, String url) throws CoreException {
+ Repository repository = new Repository();
+ repository.setId(id);
+ repository.setUrl(url);
+ repository.setLayout("default"); //$NON-NLS-1$
+
+ ArtifactRepository repo;
+ try {
+ repo = lookup(RepositorySystem.class).buildArtifactRepository(repository);
+ ArrayList<ArtifactRepository> repos = new ArrayList<ArtifactRepository>(Arrays.asList(repo));
+ injectSettings(repos);
+ } catch(InvalidRepositoryException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_create_repo, ex));
+ }
+ return repo;
+ }
+
+ public List<ArtifactRepository> getArtifactRepositories() throws CoreException {
+ return getArtifactRepositories(true);
+ }
+
+ public List<ArtifactRepository> getArtifactRepositories(boolean injectSettings) throws CoreException {
+ ArrayList<ArtifactRepository> repositories = new ArrayList<ArtifactRepository>();
+ for(Profile profile : getActiveProfiles()) {
+ addArtifactRepositories(repositories, profile.getRepositories());
+ }
+
+ addDefaultRepository(repositories);
+
+ if(injectSettings) {
+ injectSettings(repositories);
+ }
+
+ return removeDuplicateRepositories(repositories);
+ }
+
+ private List<ArtifactRepository> removeDuplicateRepositories(ArrayList<ArtifactRepository> repositories) {
+ ArrayList<ArtifactRepository> result = new ArrayList<ArtifactRepository>();
+
+ HashSet<String> keys = new HashSet<String>();
+ for(ArtifactRepository repository : repositories) {
+ StringBuilder key = new StringBuilder();
+ if(repository.getId() != null) {
+ key.append(repository.getId());
+ }
+ key.append(':').append(repository.getUrl()).append(':');
+ if(repository.getAuthentication() != null && repository.getAuthentication().getUsername() != null) {
+ key.append(repository.getAuthentication().getUsername());
+ }
+ if(keys.add(key.toString())) {
+ result.add(repository);
+ }
+ }
+ return result;
+ }
+
+ private void injectSettings(ArrayList<ArtifactRepository> repositories) throws CoreException {
+ Settings settings = getSettings();
+
+ lookup(RepositorySystem.class).injectMirror(repositories, getMirrors());
+ lookup(RepositorySystem.class).injectProxy(repositories, settings.getProxies());
+ lookup(RepositorySystem.class).injectAuthentication(repositories, settings.getServers());
+ }
+
+ private void addDefaultRepository(ArrayList<ArtifactRepository> repositories) throws CoreException {
+ for(ArtifactRepository repository : repositories) {
+ if(RepositorySystem.DEFAULT_REMOTE_REPO_ID.equals(repository.getId())) {
+ return;
+ }
+ }
+ try {
+ repositories.add(0, lookup(RepositorySystem.class).createDefaultRemoteRepository());
+ } catch(InvalidRepositoryException ex) {
+ MavenLogger.log("Unexpected exception", ex);
+ }
+ }
+
+ private void addArtifactRepositories(ArrayList<ArtifactRepository> artifactRepositories, List<Repository> repositories)
+ throws CoreException {
+ for(Repository repository : repositories) {
+ try {
+ ArtifactRepository artifactRepository = lookup(RepositorySystem.class).buildArtifactRepository(repository);
+ artifactRepositories.add(artifactRepository);
+ } catch(InvalidRepositoryException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenImpl_error_read_settings,
+ ex));
+ }
+ }
+ }
+
+ private List<Profile> getActiveProfiles() throws CoreException {
+ Settings settings = getSettings();
+ List<String> activeProfilesIds = settings.getActiveProfiles();
+ ArrayList<Profile> activeProfiles = new ArrayList<Profile>();
+ for(org.apache.maven.settings.Profile settingsProfile : settings.getProfiles()) {
+ if((settingsProfile.getActivation() != null && settingsProfile.getActivation().isActiveByDefault())
+ || activeProfilesIds.contains(settingsProfile.getId())) {
+ Profile profile = SettingsUtils.convertFromSettingsProfile(settingsProfile);
+ activeProfiles.add(profile);
+ }
+ }
+ return activeProfiles;
+ }
+
+ public List<ArtifactRepository> getPluginArtifactRepositories() throws CoreException {
+ return getPluginArtifactRepositories(true);
+ }
+
+ public List<ArtifactRepository> getPluginArtifactRepositories(boolean injectSettings) throws CoreException {
+ ArrayList<ArtifactRepository> repositories = new ArrayList<ArtifactRepository>();
+ for(Profile profile : getActiveProfiles()) {
+ addArtifactRepositories(repositories, profile.getPluginRepositories());
+ }
+ addDefaultRepository(repositories);
+
+ if(injectSettings) {
+ injectSettings(repositories);
+ }
+
+ return removeDuplicateRepositories(repositories);
+ }
+
+ public Mirror getMirror(ArtifactRepository repo) throws CoreException {
+ MavenExecutionRequest request = createExecutionRequest(new NullProgressMonitor());
+ populateDefaults(request);
+ return lookup(RepositorySystem.class).getMirror(repo, request.getMirrors());
+ };
+
+ public void populateDefaults(MavenExecutionRequest request) throws CoreException {
+ try {
+ lookup(MavenExecutionRequestPopulator.class).populateDefaults(request);
+ } catch(MavenExecutionRequestPopulationException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_read_config, ex));
+ }
+ }
+
+ public List<Mirror> getMirrors() throws CoreException {
+ MavenExecutionRequest request = createExecutionRequest(null);
+ populateDefaults(request);
+ return request.getMirrors();
+ }
+
+ public void addSettingsChangeListener(ISettingsChangeListener listener) {
+ settingsListeners.add(listener);
+ }
+
+ public void removeSettingsChangeListener(ISettingsChangeListener listener) {
+ settingsListeners.remove(listener);
+ }
+
+ public void addLocalRepositoryListener(ILocalRepositoryListener listener) {
+ localRepositoryListeners.add(listener);
+ }
+
+ public void removeLocalRepositoryListener(ILocalRepositoryListener listener) {
+ localRepositoryListeners.remove(listener);
+ }
+
+ public List<ILocalRepositoryListener> getLocalRepositoryListeners() {
+ return localRepositoryListeners;
+ }
+
+ @SuppressWarnings("deprecation")
+ public WagonTransferListenerAdapter createTransferListener(IProgressMonitor monitor) {
+ return new WagonTransferListenerAdapter(this, monitor, console);
+ }
+
+ public TransferListener createArtifactTransferListener(IProgressMonitor monitor) {
+ return new ArtifactTransferListenerAdapter(this, monitor, console);
+ }
+
+ public synchronized PlexusContainer getPlexusContainer() throws CoreException {
+ if(plexus == null) {
+ try {
+ plexus = newPlexusContainer();
+ plexus.setLoggerManager(new EclipseLoggerManager(console, mavenConfiguration));
+ } catch(PlexusContainerException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_init_maven, ex));
+ }
+ }
+ return plexus;
+ }
+
+ public ProxyInfo getProxyInfo(String protocol) throws CoreException {
+ Settings settings = getSettings();
+
+ for(Proxy proxy : settings.getProxies()) {
+ if(proxy.isActive() && protocol.equalsIgnoreCase(proxy.getProtocol())) {
+ ProxyInfo proxyInfo = new ProxyInfo();
+ proxyInfo.setType(proxy.getProtocol());
+ proxyInfo.setHost(proxy.getHost());
+ proxyInfo.setPort(proxy.getPort());
+ proxyInfo.setNonProxyHosts(proxy.getNonProxyHosts());
+ proxyInfo.setUserName(proxy.getUsername());
+ proxyInfo.setPassword(proxy.getPassword());
+ return proxyInfo;
+ }
+ }
+
+ return null;
+ }
+
+ public List<MavenProject> getSortedProjects(List<MavenProject> projects) throws CoreException {
+ try {
+ ProjectSorter rm = new ProjectSorter(projects);
+ return rm.getSortedProjects();
+ } catch(CycleDetectedException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, Messages.MavenImpl_error_sort, ex));
+ } catch(DuplicateProjectException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, Messages.MavenImpl_error_sort, ex));
+ }
+ }
+
+ public String resolvePluginVersion(String groupId, String artifactId, MavenSession session) throws CoreException {
+ Plugin plugin = new Plugin();
+ plugin.setGroupId(groupId);
+ plugin.setArtifactId(artifactId);
+ PluginVersionRequest request = new DefaultPluginVersionRequest(plugin, session);
+ try {
+ return lookup(PluginVersionResolver.class).resolve(request).getVersion();
+ } catch(PluginVersionResolutionException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, ex.getMessage(), ex));
+ }
+ }
+
+ private <T> T lookup(Class<T> clazz) throws CoreException {
+ try {
+ return getPlexusContainer().lookup(clazz);
+ } catch(ComponentLookupException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.MavenImpl_error_lookup, ex));
+ }
+ }
+
+ private static DefaultPlexusContainer newPlexusContainer() throws PlexusContainerException {
+ ContainerConfiguration mavenCoreCC = new DefaultContainerConfiguration().setClassWorld(
+ new ClassWorld(MAVEN_CORE_REALM_ID, ClassWorld.class.getClassLoader())).setName(
+ "mavenCore"); //$NON-NLS-1$
+
+ mavenCoreCC.setAutoWiring(true);
+
+ return new DefaultPlexusContainer(mavenCoreCC, new ExtensionModule());
+ }
+
+ public synchronized void disposeContainer() {
+ if(plexus != null) {
+ plexus.dispose();
+ }
+ }
+
+ public ClassLoader getProjectRealm(MavenProject project) {
+ ClassLoader classLoader = project.getClassRealm();
+ if(classLoader == null) {
+ classLoader = plexus.getContainerRealm();
+ }
+ return classLoader;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenWorkspaceRuntime.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenWorkspaceRuntime.java
new file mode 100644
index 00000000..f7db67ec
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenWorkspaceRuntime.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import java.io.File;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.IMavenLauncherConfiguration;
+import org.eclipse.m2e.core.embedder.MavenRuntime;
+import org.eclipse.m2e.core.embedder.MavenRuntimeManager;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+
+/**
+ * Maven 3.0-SNAPSHOT runtime loaded from the Eclipse Workspace
+ *
+ * @author Eugene Kuleshov
+ * @author Igor Fedorenko
+ */
+public class MavenWorkspaceRuntime implements MavenRuntime {
+
+ private static final ArtifactKey MAVEN_DISTRIBUTION = new ArtifactKey("org.apache.maven", "apache-maven", "3.0", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ private static final ArtifactKey PLEXUS_CLASSWORLDS = new ArtifactKey("org.codehaus.plexus", "plexus-classworlds", null, null); //$NON-NLS-1$ //$NON-NLS-2$
+
+ private static final String MAVEN_EXECUTOR_CLASS = "org.apache.maven.cli.MavenCli"; //$NON-NLS-1$
+
+ private static final String PLEXUS_CLASSWORLD_NAME = "plexus.core"; //$NON-NLS-1$
+
+ private MavenProjectManager projectManager;
+
+ public MavenWorkspaceRuntime(MavenProjectManager projectManager) {
+ this.projectManager = projectManager;
+ }
+
+ public String getLocation() {
+ return MavenRuntimeManager.WORKSPACE;
+ }
+
+ public String getSettings() {
+ return null;
+ }
+
+ public boolean isEditable() {
+ return false;
+ }
+
+ public boolean isAvailable() {
+ return getMavenDistribution() != null;
+ }
+
+ private IMavenProjectFacade getMavenDistribution() {
+ for (IMavenProjectFacade facade : projectManager.getProjects()) {
+ ArtifactKey artifactKey = facade.getArtifactKey();
+ if (MAVEN_DISTRIBUTION.getGroupId().equals(artifactKey.getGroupId()) //
+ && MAVEN_DISTRIBUTION.getArtifactId().equals(artifactKey.getArtifactId())//
+ && artifactKey.getVersion().startsWith(MAVEN_DISTRIBUTION.getVersion())) {
+ return facade;
+ }
+ }
+ return null;
+ }
+
+ public void createLauncherConfiguration(IMavenLauncherConfiguration collector, IProgressMonitor monitor) throws CoreException {
+ IMavenProjectFacade maven = getMavenDistribution();
+ if (maven != null) {
+ MavenProject mavenProject = maven.getMavenProject(monitor);
+
+ collector.setMainType(MAVEN_EXECUTOR_CLASS, PLEXUS_CLASSWORLD_NAME);
+
+ collector.addRealm(PLEXUS_CLASSWORLD_NAME);
+
+ Set<Artifact> artifacts = mavenProject.getArtifacts();
+
+ Artifact launcherArtifact = null;
+
+ for (Artifact artifact : artifacts) {
+ if (Artifact.SCOPE_TEST.equals(artifact.getScope())) {
+ continue;
+ }
+
+ if (PLEXUS_CLASSWORLDS.getGroupId().equals(artifact.getGroupId()) && PLEXUS_CLASSWORLDS.getArtifactId().equals(artifact.getArtifactId())) {
+ launcherArtifact = artifact;
+ continue;
+ }
+
+ addArtifact(collector, artifact);
+ }
+
+ if (launcherArtifact != null) {
+ collector.addRealm(IMavenLauncherConfiguration.LAUNCHER_REALM);
+ addArtifact(collector, launcherArtifact);
+ }
+ }
+
+ // XXX throw something at the caller!
+ }
+
+ private void addArtifact(IMavenLauncherConfiguration collector, Artifact artifact) throws CoreException {
+ IMavenProjectFacade facade = projectManager.getMavenProject(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion());
+
+ if (facade != null) {
+ collector.addProjectEntry(facade);
+ } else {
+ File file = artifact.getFile();
+ if (file != null) {
+ collector.addArchiveEntry(file.getAbsolutePath());
+ }
+ }
+ }
+
+ public String toString() {
+ return "Workspace (" + getVersion() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public String getVersion() {
+ IMavenProjectFacade maven = getMavenDistribution();
+ if (maven != null) {
+ return maven.getArtifactKey().getVersion();
+ }
+ return MAVEN_DISTRIBUTION.getVersion();
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/WagonTransferListenerAdapter.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/WagonTransferListenerAdapter.java
new file mode 100644
index 00000000..7d5b19c5
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/WagonTransferListenerAdapter.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.embedder;
+
+import java.io.File;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
+import org.apache.maven.index.artifact.Gav;
+import org.apache.maven.index.artifact.GavCalculator;
+import org.apache.maven.index.artifact.M2GavCalculator;
+import org.apache.maven.wagon.Wagon;
+import org.apache.maven.wagon.events.TransferEvent;
+import org.apache.maven.wagon.events.TransferListener;
+import org.apache.maven.wagon.repository.Repository;
+
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.ILocalRepositoryListener;
+
+/**
+ * @author Eugene Kuleshov
+ */
+final class WagonTransferListenerAdapter extends AbstractTransferListenerAdapter implements TransferListener {
+ // TODO this is just wrong!
+ private final GavCalculator gavCalculator = new M2GavCalculator();
+
+ WagonTransferListenerAdapter(MavenImpl maven, IProgressMonitor monitor, MavenConsole console) {
+ super(maven, monitor, console);
+ }
+
+ public void transferInitiated(TransferEvent e) {
+ // System.err.println( "init "+e.getWagon().getRepository()+"/"+e.getResource().getName());
+ transferInitiated((String) null);
+ }
+
+ public void transferStarted(TransferEvent e) {
+ StringBuilder sb = new StringBuilder();
+ if(e.getWagon() != null && e.getWagon().getRepository() != null) {
+ Wagon wagon = e.getWagon();
+ Repository repository = wagon.getRepository();
+ String repositoryId = repository.getId();
+ sb.append(repositoryId).append(" : "); //$NON-NLS-1$
+ }
+ sb.append(e.getResource().getName());
+ transferStarted(sb.toString());
+ }
+
+ public void transferProgress(TransferEvent e, byte[] buffer, int length) {
+ long total = e.getResource().getContentLength();
+ String artifactUrl = e.getWagon().getRepository() + "/" + e.getResource().getName(); //$NON-NLS-1$
+
+ transferProgress(artifactUrl, total, length);
+ }
+
+ public void transferCompleted(TransferEvent e) {
+ String artifactUrl = e.getWagon().getRepository() + "/" + e.getResource().getName(); //$NON-NLS-1$
+ transferCompleted(artifactUrl);
+
+ notifyLocalRepositoryListeners(e);
+ }
+
+ public void transferError(TransferEvent e) {
+ transferError(e.getWagon().getRepository() + "/" + e.getResource().getName(), e.getException()); //$NON-NLS-1$
+ }
+
+ public void debug(String message) {
+ // System.err.println( "debug "+message);
+ }
+
+ private void notifyLocalRepositoryListeners(TransferEvent e) {
+ try {
+ ArtifactRepository localRepository = maven.getLocalRepository();
+
+ if (!(localRepository.getLayout() instanceof DefaultRepositoryLayout)) {
+ return;
+ }
+
+ String repoBasepath = new File(localRepository.getBasedir()).getCanonicalPath();
+
+ File artifactFile = e.getLocalFile();
+
+ if (artifactFile == null) {
+ return;
+ }
+
+ String artifactPath = artifactFile.getCanonicalPath();
+ if (!artifactPath.startsWith(repoBasepath)) {
+ return;
+ }
+
+ artifactPath = artifactPath.substring(repoBasepath.length());
+ Gav gav = gavCalculator.pathToGav(artifactPath);
+ ArtifactKey artifactKey = new ArtifactKey(gav.getGroupId(), gav.getArtifactId(), gav.getVersion(), gav.getClassifier());
+
+ File repoBasedir = new File(localRepository.getBasedir()).getCanonicalFile();
+
+ for (ILocalRepositoryListener listener : maven.getLocalRepositoryListeners()) {
+ listener.artifactInstalled(repoBasedir, artifactKey, artifactFile);
+ }
+ } catch (Exception ex) {
+ MavenLogger.log("Could not notify local repository listeners", ex);
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/ArtifactScanningMonitor.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/ArtifactScanningMonitor.java
new file mode 100644
index 00000000..adf3f0de
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/ArtifactScanningMonitor.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.index;
+
+import java.io.File;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.index.ArtifactContext;
+import org.apache.maven.index.ArtifactScanningListener;
+import org.apache.maven.index.ScanningResult;
+import org.apache.maven.index.context.IndexingContext;
+
+import org.eclipse.m2e.core.core.MavenConsole;
+
+class ArtifactScanningMonitor implements ArtifactScanningListener {
+
+ private static final long THRESHOLD = 1 * 1000L;
+
+ //private final IndexInfo indexInfo;
+
+ private final IProgressMonitor monitor;
+
+ private final MavenConsole console;
+
+ private long timestamp = System.currentTimeMillis();
+
+ private File repositoryDir;
+
+ ArtifactScanningMonitor(File repositoryDir, IProgressMonitor monitor, MavenConsole console) {
+ //this.indexInfo = indexInfo;
+ this.repositoryDir = repositoryDir;
+ this.monitor = monitor;
+ this.console = console;
+ }
+
+ public void scanningStarted(IndexingContext ctx) {
+ }
+
+ public void scanningFinished(IndexingContext ctx, ScanningResult result) {
+ }
+
+ public void artifactDiscovered(ArtifactContext ac) {
+ long current = System.currentTimeMillis();
+ if((current - timestamp) > THRESHOLD) {
+ // String id = info.groupId + ":" + info.artifactId + ":" + info.version;
+ String id = ac.getPom().getAbsolutePath().substring(
+ this.repositoryDir.getAbsolutePath().length());
+ this.monitor.setTaskName(id);
+ this.timestamp = current;
+ }
+ }
+
+ public void artifactError(ArtifactContext ac, Exception e) {
+ String id = ac.getPom().getAbsolutePath().substring(repositoryDir.getAbsolutePath().length());
+ console.logError(id + " " + e.getMessage()); //$NON-NLS-1$
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/AsyncFetcher.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/AsyncFetcher.java
new file mode 100644
index 00000000..458df72d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/AsyncFetcher.java
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.index;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.net.HttpURLConnection;
+
+import com.ning.http.client.AsyncHandler;
+import com.ning.http.client.AsyncHttpClient;
+import com.ning.http.client.AsyncHttpClientConfig;
+import com.ning.http.client.HttpResponseBodyPart;
+import com.ning.http.client.HttpResponseHeaders;
+import com.ning.http.client.HttpResponseStatus;
+import com.ning.http.client.ProxyServer;
+import com.ning.http.client.Realm;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.io.RawInputStreamFacade;
+
+import org.apache.maven.index.updater.AbstractResourceFetcher;
+import org.apache.maven.wagon.authentication.AuthenticationInfo;
+import org.apache.maven.wagon.proxy.ProxyInfo;
+import org.apache.maven.wagon.proxy.ProxyUtils;
+import org.apache.maven.wagon.repository.Repository;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * A resource fetcher using Async HTTP Client.
+ *
+ * @author Benjamin Bentmann
+ */
+class AsyncFetcher extends AbstractResourceFetcher {
+
+ private final AuthenticationInfo authInfo;
+
+ private final ProxyInfo proxyInfo;
+
+ final IProgressMonitor monitor;
+
+ private AsyncHttpClient httpClient;
+
+ private Realm authRealm;
+
+ private ProxyServer proxyServer;
+
+ private String baseUrl;
+
+ public AsyncFetcher(final AuthenticationInfo authInfo, final ProxyInfo proxyInfo, final IProgressMonitor monitor) {
+ this.authInfo = authInfo;
+ this.proxyInfo = proxyInfo;
+ this.monitor = (monitor != null) ? monitor : new NullProgressMonitor();
+ }
+
+ private static Realm toRealm(AuthenticationInfo authInfo) {
+ Realm realm = null;
+
+ if(authInfo != null && authInfo.getUserName() != null && authInfo.getUserName().length() > 0) {
+ realm = new Realm.RealmBuilder().setPrincipal(authInfo.getUserName()).setPassword(authInfo.getPassword())
+ .setUsePreemptiveAuth(false).build();
+ }
+
+ return realm;
+ }
+
+ private static ProxyServer toProxyServer(ProxyInfo proxyInfo) {
+ ProxyServer proxyServer = null;
+
+ if(proxyInfo != null) {
+ ProxyServer.Protocol protocol = "https".equalsIgnoreCase(proxyInfo.getType()) ? ProxyServer.Protocol.HTTPS //$NON-NLS-1$
+ : ProxyServer.Protocol.HTTP;
+ proxyServer = new ProxyServer(protocol, proxyInfo.getHost(), proxyInfo.getPort(), proxyInfo.getUserName(),
+ proxyInfo.getPassword());
+ }
+
+ return proxyServer;
+ }
+
+ private ProxyServer getProxyServer(ProxyInfo proxyInfo, String url) {
+ if(proxyInfo != null) {
+ Repository repo = new Repository("id", url); //$NON-NLS-1$
+ if(!ProxyUtils.validateNonProxyHosts(proxyInfo, repo.getHost())) {
+ return toProxyServer(proxyInfo);
+ }
+ }
+ return null;
+ }
+
+ public void connect(String id, String url) {
+ AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder();
+ configBuilder.setUserAgent("M2Eclipse/" + MavenPlugin.getQualifiedVersion()); //$NON-NLS-1$
+ configBuilder.setConnectionTimeoutInMs(15 * 1000);
+ configBuilder.setRequestTimeoutInMs(60 * 1000);
+ configBuilder.setCompressionEnabled(true);
+ configBuilder.setFollowRedirects(true);
+
+ httpClient = new AsyncHttpClient(configBuilder.build());
+
+ baseUrl = url.endsWith("/") ? url : (url + '/'); //$NON-NLS-1$
+ authRealm = toRealm(authInfo);
+ proxyServer = getProxyServer(proxyInfo, url);
+ }
+
+ public void disconnect() {
+ authRealm = null;
+ proxyServer = null;
+ baseUrl = null;
+ if(httpClient != null) {
+ httpClient.close();
+ }
+ httpClient = null;
+ }
+
+ @SuppressWarnings("deprecation")
+ public void retrieve(String name, File targetFile) throws IOException, FileNotFoundException {
+ InputStream is = retrieve(name);
+ try {
+ FileUtils.copyStreamToFile(new RawInputStreamFacade(is), targetFile);
+ } finally {
+ IOUtil.close(is);
+ }
+ }
+
+ public InputStream retrieve(String name) throws IOException, FileNotFoundException {
+ String url = buildUrl(baseUrl, name);
+
+ monitor.subTask(NLS.bind(Messages.AsyncFetcher_task_fetching, url));
+
+ PipedErrorInputStream pis = new PipedErrorInputStream();
+
+ httpClient.prepareGet(url).setRealm(authRealm).setProxyServer(proxyServer).execute(new RequestHandler(url, pis));
+
+ return pis;
+ }
+
+ private static String buildUrl(String baseUrl, String resourceName) {
+ String url = baseUrl;
+
+ if(resourceName.startsWith("/")) { //$NON-NLS-1$
+ url += resourceName.substring(1);
+ } else {
+ url += resourceName;
+ }
+
+ return url;
+ }
+
+ static final class PipedErrorInputStream extends PipedInputStream {
+
+ private volatile Throwable error;
+
+ public PipedErrorInputStream() {
+ buffer = new byte[1024 * 128];
+ }
+
+ public void setError(Throwable t) {
+ if(error == null) {
+ error = t;
+ }
+ }
+
+ private void checkError() throws IOException {
+ if(error != null) {
+ throw (IOException) new IOException(error.getMessage()).initCause(error);
+ }
+ }
+
+ public synchronized int read() throws IOException {
+ checkError();
+ int b = super.read();
+ checkError();
+ return b;
+ }
+ }
+
+ final class RequestHandler implements AsyncHandler<String> {
+
+ private final String url;
+
+ private final PipedErrorInputStream pis;
+
+ private PipedOutputStream pos;
+
+ private long total = -1;
+
+ private long transferred;
+
+ public RequestHandler(String url, PipedErrorInputStream pis) throws IOException {
+ this.url = url;
+ this.pis = pis;
+ pos = new PipedOutputStream(pis);
+ }
+
+ private void finish(Throwable exception) {
+ pis.setError(exception);
+ if(pos != null) {
+ try {
+ pos.close();
+ } catch(IOException ex) {
+ // tried it
+ }
+ pos = null;
+ }
+ }
+
+ private STATE checkCancel() {
+ if(monitor.isCanceled()) {
+ finish(new IOException(Messages.AsyncFetcher_error_cancelled));
+ return STATE.ABORT;
+ }
+ return STATE.CONTINUE;
+ }
+
+ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception {
+ if(checkCancel() == STATE.ABORT || pos == null) {
+ return STATE.ABORT;
+ }
+ int bytes = content.getBodyByteBuffer().remaining();
+ content.writeTo(pos);
+ if(total > 0) {
+ transferred += bytes;
+ monitor.subTask(NLS.bind(Messages.AsyncFetcher_task_fetching2,url, transferred * 100 / total));
+ }
+ return STATE.CONTINUE;
+ }
+
+ public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception {
+ if(checkCancel() == STATE.ABORT) {
+ return STATE.ABORT;
+ }
+ try {
+ total = Long.parseLong(headers.getHeaders().getFirstValue("Content-Length")); //$NON-NLS-1$
+ } catch(Exception e) {
+ total = -1;
+ }
+ return STATE.CONTINUE;
+ }
+
+ public STATE onStatusReceived(HttpResponseStatus status) throws Exception {
+ if(status.getStatusCode() != HttpURLConnection.HTTP_OK) {
+ finish(new IOException(NLS.bind(Messages.AsyncFetcher_error_server, status.getStatusCode(), status.getStatusText())));
+ return STATE.ABORT;
+ }
+ if(checkCancel() == STATE.ABORT) {
+ return STATE.ABORT;
+ }
+ return STATE.CONTINUE;
+ }
+
+ public String onCompleted() throws Exception {
+ monitor.subTask(""); //$NON-NLS-1$
+ finish(null);
+ return ""; //$NON-NLS-1$
+ }
+
+ public void onThrowable(Throwable t) {
+ finish(t);
+ }
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/CompositeIndex.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/CompositeIndex.java
new file mode 100644
index 00000000..1d934310
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/CompositeIndex.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.index;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.index.SearchExpression;
+
+
+/**
+ * CompositeIndex
+ *
+ * @author igor
+ */
+public class CompositeIndex implements IIndex {
+
+ private List<IIndex> indexes;
+
+ public CompositeIndex(List<IIndex> indexes) {
+ this.indexes = indexes;
+ }
+
+ public IndexedArtifactFile getIndexedArtifactFile(ArtifactKey artifact) throws CoreException {
+ for(IIndex index : indexes) {
+ IndexedArtifactFile aif = index.getIndexedArtifactFile(artifact);
+ if(aif != null) {
+ // first one wins
+ return aif;
+ }
+ }
+
+ // did not find anything
+ return null;
+ }
+
+ public IndexedArtifactFile identify(File file) throws CoreException {
+ for(IIndex index : indexes) {
+ IndexedArtifactFile aif = index.identify(file);
+ if(aif != null) {
+ // first one wins
+ return aif;
+ }
+ }
+
+ // did not find anything
+ return null;
+ }
+
+ public Collection<IndexedArtifact> find(SearchExpression groupId, SearchExpression artifactId,
+ SearchExpression version, SearchExpression packaging) throws CoreException {
+ Set<IndexedArtifact> result = new LinkedHashSet<IndexedArtifact>();
+ for(IIndex index : indexes) {
+ Collection<IndexedArtifact> findResults = index.find(groupId, artifactId, version, packaging);
+ if(findResults != null) {
+ result.addAll(findResults);
+ }
+ }
+ return result;
+ }
+
+ public Collection<IndexedArtifact> find(Collection<SearchExpression> groupId,
+ Collection<SearchExpression> artifactId, Collection<SearchExpression> version,
+ Collection<SearchExpression> packaging) throws CoreException {
+ Set<IndexedArtifact> result = new LinkedHashSet<IndexedArtifact>();
+ for(IIndex index : indexes) {
+ Collection<IndexedArtifact> findResults = index.find(groupId, artifactId, version, packaging);
+ if(findResults != null) {
+ result.addAll(findResults);
+ }
+ }
+ return result;
+ }
+
+ public Map<String, IndexedArtifact> search(SearchExpression term, String searchType) throws CoreException {
+ Map<String, IndexedArtifact> result = new HashMap<String, IndexedArtifact>();
+ for(IIndex index : indexes) {
+ Map<String, IndexedArtifact> iresult = index.search(term, searchType);
+ if(iresult != null) {
+ result.putAll(iresult);
+ }
+ }
+ return result;
+ }
+
+ public Map<String, IndexedArtifact> search(SearchExpression term, String searchType, int classifier)
+ throws CoreException {
+ Map<String, IndexedArtifact> result = new HashMap<String, IndexedArtifact>();
+ for(IIndex index : indexes) {
+ Map<String, IndexedArtifact> iresult = index.search(term, searchType, classifier);
+ if(iresult != null) {
+ result.putAll(iresult);
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/EquinoxLock.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/EquinoxLock.java
new file mode 100644
index 00000000..4aa82f6e
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/EquinoxLock.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.index;
+
+import org.eclipse.core.runtime.internal.adaptor.Locker;
+
+import org.apache.maven.index.fs.Lock;
+
+@SuppressWarnings("restriction")
+public class EquinoxLock
+ implements Lock
+{
+
+ private final Locker lock;
+
+ public EquinoxLock( Locker lock )
+ {
+ this.lock = lock;
+ }
+
+ public void release()
+ {
+ lock.release();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/EquinoxLocker.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/EquinoxLocker.java
new file mode 100644
index 00000000..e88c7e0c
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/EquinoxLocker.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.index;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.core.runtime.internal.adaptor.BasicLocation;
+import org.eclipse.osgi.util.NLS;
+
+import org.apache.maven.index.fs.Lock;
+import org.apache.maven.index.fs.Locker;
+
+@SuppressWarnings("restriction")
+public class EquinoxLocker
+ implements Locker
+{
+
+ public Lock lock( File directory )
+ throws IOException
+ {
+ org.eclipse.core.runtime.internal.adaptor.Locker lock = BasicLocation.createLocker(new File( directory, LOCK_FILE ), null );
+
+ if ( lock.lock() )
+ {
+ return new EquinoxLock( lock );
+ }
+
+ throw new IOException( NLS.bind("Could not acquire lock on directory {0}", directory ));
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexUpdaterJob.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexUpdaterJob.java
new file mode 100644
index 00000000..a14760f6
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexUpdaterJob.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.index;
+
+import java.util.ArrayList;
+import java.util.Stack;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.ui.progress.IProgressConstants;
+
+import org.eclipse.m2e.core.actions.OpenMavenConsoleAction;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.jobs.IBackgroundProcessingQueue;
+
+class IndexUpdaterJob extends Job implements IBackgroundProcessingQueue {
+
+ public static class IndexUpdaterRule implements ISchedulingRule {
+
+ public boolean contains(ISchedulingRule rule) {
+ return rule == this;
+ }
+
+ public boolean isConflicting(ISchedulingRule rule) {
+ return rule == this;
+ }
+
+ }
+
+ public interface IndexCommand {
+ abstract void run(IProgressMonitor monitor) throws CoreException;
+ }
+
+ private final Stack<IndexUpdaterJob.IndexCommand> updateQueue = new Stack<IndexUpdaterJob.IndexCommand>();
+
+ public IndexUpdaterJob(NexusIndexManager indexManager, MavenConsole console) {
+ super(Messages.IndexUpdaterJob_title);
+ setProperty(IProgressConstants.ACTION_PROPERTY, new OpenMavenConsoleAction());
+ setRule(new IndexUpdaterRule());
+ }
+
+ public void addCommand(IndexUpdaterJob.IndexCommand indexCommand) {
+ updateQueue.add(indexCommand);
+ }
+
+ public IStatus run(IProgressMonitor monitor) {
+ monitor.beginTask(getName(), IProgressMonitor.UNKNOWN);
+
+ ArrayList<IStatus> problems = new ArrayList<IStatus>();
+
+ while(!updateQueue.isEmpty()) {
+ if (monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+
+ IndexUpdaterJob.IndexCommand command = updateQueue.pop();
+ try {
+ command.run(monitor);
+ } catch(CoreException ex) {
+ problems.add(ex.getStatus());
+ }
+ }
+
+ monitor.done();
+
+ return problems.isEmpty()? Status.OK_STATUS: new MultiStatus(IMavenConstants.PLUGIN_ID, -1, problems.toArray(new IStatus[problems.size()]), null, null);
+ }
+
+ public boolean isEmpty() {
+ return updateQueue.isEmpty();
+ }
+
+} \ No newline at end of file
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexedArtifactGroup.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexedArtifactGroup.java
new file mode 100644
index 00000000..96dc8e65
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexedArtifactGroup.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.index;
+
+import java.util.LinkedHashMap;
+
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.repository.IRepository;
+
+
+public class IndexedArtifactGroup implements Comparable<IndexedArtifactGroup>{
+ private final IRepository repository;
+ private final String prefix;
+ private final LinkedHashMap<String, IndexedArtifactGroup> nodes = new LinkedHashMap<String, IndexedArtifactGroup>();
+ private final LinkedHashMap<String, IndexedArtifact> files = new LinkedHashMap<String, IndexedArtifact>();
+
+ public IndexedArtifactGroup(IRepository repository, String prefix) {
+ this.repository = repository;
+ this.prefix = prefix;
+ }
+
+ public LinkedHashMap<String, IndexedArtifactGroup> getNodes() {
+ return nodes;
+ }
+
+ public LinkedHashMap<String, IndexedArtifact> getFiles() {
+ return files;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public IRepository getRepository() {
+ return this.repository;
+ }
+
+ /*
+ * Compare the groups by prefix
+ */
+ public int compareTo(IndexedArtifactGroup o) {
+ if(o == null){
+ return -1;
+ }
+ return getPrefix().compareToIgnoreCase(o.getPrefix());
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexesExtensionReader.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexesExtensionReader.java
new file mode 100644
index 00000000..3e5bd76e
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexesExtensionReader.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.index;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.internal.repository.IRepositoryDiscoverer;
+import org.eclipse.m2e.core.internal.repository.RepositoryInfo;
+import org.eclipse.m2e.core.internal.repository.RepositoryRegistry;
+import org.eclipse.m2e.core.repository.IRepositoryRegistry;
+
+/**
+ * IndexesExtensionReader
+ *
+ * @author igor
+ */
+public class IndexesExtensionReader implements IRepositoryDiscoverer {
+
+ private static final String EXTENSION_INDEXES = IMavenConstants.PLUGIN_ID + ".indexes"; //$NON-NLS-1$
+
+ private static final String ELEMENT_INDEX = "index"; //$NON-NLS-1$
+
+ private static final String ATTR_INDEX_ID = "indexId"; //$NON-NLS-1$
+
+// private static final String ATTR_INDEX_ARCHIVE = "archive";
+
+ private static final String ATTR_REPOSITORY_URL = "repositoryUrl"; //$NON-NLS-1$
+
+// private static final String ATTR_UPDATE_URL = "updateUrl";
+
+ private static final String ATTR_IS_SHORT = "isShort"; //$NON-NLS-1$
+
+ private final NexusIndexManager indexManager;
+
+ public IndexesExtensionReader(NexusIndexManager indexManager) {
+ this.indexManager = indexManager;
+ }
+
+ public void addRepositories(RepositoryRegistry registry, IProgressMonitor monitor) throws CoreException {
+ IExtensionPoint indexesExtensionPoint = Platform.getExtensionRegistry().getExtensionPoint(EXTENSION_INDEXES);
+ if(indexesExtensionPoint != null) {
+ IExtension[] indexesExtensions = indexesExtensionPoint.getExtensions();
+ for(IExtension extension : indexesExtensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for(IConfigurationElement element : elements) {
+ if(element.getName().equals(ELEMENT_INDEX)) {
+ processIndexElement(registry, element, monitor);
+ }
+ }
+ }
+ }
+ }
+
+ private void processIndexElement(RepositoryRegistry registry, IConfigurationElement element, IProgressMonitor monitor) throws CoreException {
+ String indexId = element.getAttribute(ATTR_INDEX_ID);
+ String repositoryUrl = element.getAttribute(ATTR_REPOSITORY_URL);
+ boolean isShort = Boolean.valueOf(element.getAttribute(ATTR_IS_SHORT)).booleanValue();
+
+// String indexUpdateUrl = element.getAttribute(ATTR_UPDATE_URL);
+// String archive = element.getAttribute(ATTR_INDEX_ARCHIVE);
+
+ RepositoryInfo repository = new RepositoryInfo(indexId, repositoryUrl, IRepositoryRegistry.SCOPE_UNKNOWN, null);
+ registry.addRepository(repository, monitor);
+
+ // for consistency, always process indexes using our background thread
+ indexManager.setIndexDetails(repository, isShort? NexusIndex.DETAILS_MIN: NexusIndex.DETAILS_FULL, null/*async*/);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexingTransferListener.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexingTransferListener.java
new file mode 100644
index 00000000..538eeeed
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/IndexingTransferListener.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.index;
+
+import java.io.File;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.ILocalRepositoryListener;
+
+public class IndexingTransferListener implements ILocalRepositoryListener {
+
+ private final NexusIndexManager indexManager;
+
+ public IndexingTransferListener(NexusIndexManager indexManager) {
+ this.indexManager = indexManager;
+ }
+
+ public void artifactInstalled(File repositoryBasedir, ArtifactKey artifact, File artifactFile) {
+ NexusIndex localIndex = indexManager.getLocalIndex();
+ if(artifactFile.getName().endsWith(".jar")) { //$NON-NLS-1$
+ localIndex.addArtifact(artifactFile, artifact);
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/NexusIndex.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/NexusIndex.java
new file mode 100644
index 00000000..35b8a23e
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/NexusIndex.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.index;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.apache.lucene.search.BooleanQuery;
+
+import org.apache.maven.index.Field;
+import org.apache.maven.index.MAVEN;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IMutableIndex;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.index.SearchExpression;
+import org.eclipse.m2e.core.repository.IRepository;
+
+
+/**
+ * NexusIndex
+ *
+ * @author igor
+ */
+public class NexusIndex implements IIndex, IMutableIndex {
+
+ /**
+ * Repository index is disabled.
+ */
+ public static final String DETAILS_DISABLED = "off"; //$NON-NLS-1$
+
+ /**
+ * Only artifact index information is used. Classname index is disabled.
+ */
+ public static final String DETAILS_MIN = "min"; //$NON-NLS-1$
+
+ /**
+ * Both artifact and classname indexes are used.
+ */
+ public static final String DETAILS_FULL = "full"; //$NON-NLS-1$
+
+ private final NexusIndexManager indexManager;
+
+ private final IRepository repository;
+
+ private final String indexDetails;
+
+ NexusIndex(NexusIndexManager indexManager, IRepository repository, String indexDetails) {
+ this.indexManager = indexManager;
+ this.repository = repository;
+ this.indexDetails = indexDetails;
+ }
+
+ public String getRepositoryUrl() {
+ return this.repository.getUrl();
+ }
+
+ public String getIndexDetails() {
+ return this.indexDetails;
+ }
+
+ public void addArtifact(File pomFile, ArtifactKey artifactKey) {
+ indexManager.addDocument(repository, pomFile, artifactKey);
+ }
+
+ public void removeArtifact(File pomFile, ArtifactKey artifactKey) {
+ indexManager.removeDocument(repository, pomFile, artifactKey, null);
+ }
+
+ public Collection<IndexedArtifact> find(SearchExpression groupId, SearchExpression artifactId,
+ SearchExpression version, SearchExpression packaging) throws CoreException {
+ return find(wrapIfNotNull(groupId), wrapIfNotNull(artifactId), wrapIfNotNull(version), wrapIfNotNull(packaging));
+ }
+
+ /**
+ * Method wrapping one SearchExpression into a collection, if it is not null.
+ *
+ * @param sex
+ * @return
+ */
+ private Collection<SearchExpression> wrapIfNotNull(SearchExpression se) {
+ if(se == null) {
+ return null;
+ }
+ return Collections.singleton(se);
+ }
+
+ public Collection<IndexedArtifact> find(Collection<SearchExpression> groupId,
+ Collection<SearchExpression> artifactId, Collection<SearchExpression> version,
+ Collection<SearchExpression> packaging) throws CoreException {
+ BooleanQuery query = new BooleanQuery();
+
+ addQueryFromSearchExpressionCollection(query, MAVEN.PACKAGING, packaging);
+
+ addQueryFromSearchExpressionCollection(query, MAVEN.GROUP_ID, groupId);
+
+ addQueryFromSearchExpressionCollection(query, MAVEN.ARTIFACT_ID, artifactId);
+
+ addQueryFromSearchExpressionCollection(query, MAVEN.VERSION, version);
+
+ return indexManager.search(repository, query).values();
+ }
+
+ private void addQueryFromSearchExpressionCollection(final BooleanQuery query, final Field field,
+ final Collection<SearchExpression> sec) {
+ if(sec != null && !sec.isEmpty()) {
+ if(sec.size() > 1) {
+ BooleanQuery q = new BooleanQuery();
+ for(SearchExpression se : sec) {
+ q.add(indexManager.constructQuery(field, se), Occur.SHOULD);
+ }
+ query.add(q, Occur.MUST);
+ } else {
+ query.add(indexManager.constructQuery(field, sec.iterator().next()), Occur.MUST);
+ }
+ }
+ }
+
+ public IndexedArtifactFile getIndexedArtifactFile(ArtifactKey artifact) throws CoreException {
+ return indexManager.getIndexedArtifactFile(repository, artifact);
+ }
+
+ public IndexedArtifactFile identify(File file) throws CoreException {
+ return indexManager.identify(repository, file);
+ }
+
+ public void updateIndex(boolean force, IProgressMonitor monitor) throws CoreException {
+ indexManager.updateIndex(repository, force, monitor);
+ }
+
+ public void scheduleIndexUpdate(boolean force) {
+ indexManager.scheduleIndexUpdate(repository, force);
+ }
+
+ public IndexedArtifactGroup[] getRootIndexedArtifactGroups() throws CoreException {
+ return indexManager.getRootIndexedArtifactGroups(repository);
+ }
+
+ public boolean isUpdating() {
+ return indexManager.isUpdatingIndex(repository);
+ }
+
+ public IRepository getRepository() {
+ return repository;
+ }
+
+ public boolean isEnabled() {
+ return DETAILS_MIN.equals(indexDetails) || DETAILS_FULL.equals(indexDetails);
+ }
+
+ public void setIndexDetails(String details) throws CoreException {
+ indexManager.setIndexDetails(repository, details, null/*async*/);
+ }
+
+ public Map<String, IndexedArtifact> search(SearchExpression term, String searchType) throws CoreException {
+ return indexManager.search(getRepository(), term, searchType);
+ }
+
+ public Map<String, IndexedArtifact> search(SearchExpression term, String searchType, int classifier)
+ throws CoreException {
+ return indexManager.search(getRepository(), term, searchType, classifier);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/NexusIndexManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/NexusIndexManager.java
new file mode 100644
index 00000000..d41af33b
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/index/NexusIndexManager.java
@@ -0,0 +1,1312 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.index;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.WeakHashMap;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.osgi.util.NLS;
+
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.FilteredQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.QueryWrapperFilter;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+
+import org.apache.maven.index.ArtifactContext;
+import org.apache.maven.index.ArtifactContextProducer;
+import org.apache.maven.index.ArtifactInfo;
+import org.apache.maven.index.Field;
+import org.apache.maven.index.IteratorSearchRequest;
+import org.apache.maven.index.IteratorSearchResponse;
+import org.apache.maven.index.MAVEN;
+import org.apache.maven.index.NexusIndexer;
+import org.apache.maven.index.SearchType;
+import org.apache.maven.index.artifact.Gav;
+import org.apache.maven.index.artifact.IllegalArtifactCoordinateException;
+import org.apache.maven.index.context.IndexCreator;
+import org.apache.maven.index.context.IndexingContext;
+import org.apache.maven.index.creator.JarFileContentsIndexCreator;
+import org.apache.maven.index.creator.MavenArchetypeArtifactInfoIndexCreator;
+import org.apache.maven.index.creator.MavenPluginArtifactInfoIndexCreator;
+import org.apache.maven.index.creator.MinimalArtifactInfoIndexCreator;
+import org.apache.maven.index.fs.Lock;
+import org.apache.maven.index.updater.IndexUpdateRequest;
+import org.apache.maven.index.updater.IndexUpdateResult;
+import org.apache.maven.index.updater.IndexUpdater;
+import org.apache.maven.wagon.authentication.AuthenticationInfo;
+import org.apache.maven.wagon.proxy.ProxyInfo;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.ArtifactRepositoryRef;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexListener;
+import org.eclipse.m2e.core.index.IndexManager;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.index.MatchTyped;
+import org.eclipse.m2e.core.index.MatchTyped.MatchType;
+import org.eclipse.m2e.core.index.SearchExpression;
+import org.eclipse.m2e.core.index.SourcedSearchExpression;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.index.IndexUpdaterJob.IndexCommand;
+import org.eclipse.m2e.core.internal.repository.IRepositoryIndexer;
+import org.eclipse.m2e.core.project.IMavenProjectChangedListener;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectChangedEvent;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.repository.IRepository;
+import org.eclipse.m2e.core.repository.IRepositoryRegistry;
+
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class NexusIndexManager implements IndexManager, IMavenProjectChangedListener, IRepositoryIndexer {
+
+ public static final int MIN_CLASS_QUERY_LENGTH = 6;
+
+ /**
+ * Lazy instantiated nexus indexer instance.
+ */
+ private NexusIndexer indexer;
+
+ /**
+ * Lazy instantiated nexus indexer's contextProducer.
+ */
+ private ArtifactContextProducer artifactContextProducer;
+
+ /**
+ * Lock guarding lazy instantiation of indexerLock instance
+ */
+ private final Object indexerLock = new Object();
+
+ /**
+ * Lock guarding lazy instantiation of contextProducer instance
+ */
+ private final Object contextProducerLock = new Object();
+
+ private IMaven maven;
+
+ private MavenProjectManager projectManager;
+
+ private IRepositoryRegistry repositoryRegistry;
+
+ private ArrayList<IndexCreator> fullCreators = null;
+
+ private ArrayList<IndexCreator> minCreators = null;
+
+ private final MavenConsole console;
+
+ private final File baseIndexDir;
+
+ private final List<IndexListener> indexListeners = new ArrayList<IndexListener>();
+
+ private NexusIndex localIndex;
+
+ private final NexusIndex workspaceIndex;
+
+ private final IndexUpdaterJob updaterJob;
+
+ private Properties indexDetails = new Properties();
+
+ private Set<String> updatingIndexes = new HashSet<String>();
+
+ private IndexUpdater indexUpdater;
+
+ private static final EquinoxLocker locker = new EquinoxLocker();
+
+ /**
+ * Maps repository UID to the lock object associated with the repository. Entries are only added but never directly
+ * removed from the map, although jvm garbage collector may remove otherwise unused entries to reclaim the little
+ * memory they use. Never access this map directly. #getIndexLock must be used to get repository lock object.
+ */
+ private final Map<String, Object> indexLocks = new WeakHashMap<String, Object>();
+
+ public NexusIndexManager(MavenConsole console, MavenProjectManager projectManager,
+ IRepositoryRegistry repositoryRegistry, File stateDir) {
+ this.console = console;
+ this.projectManager = projectManager;
+ this.repositoryRegistry = repositoryRegistry;
+ this.baseIndexDir = new File(stateDir, "nexus"); //$NON-NLS-1$
+
+ this.maven = MavenPlugin.getDefault().getMaven();
+ this.indexUpdater = MavenPlugin.getDefault().getIndexUpdater();
+
+ this.updaterJob = new IndexUpdaterJob(this, console);
+
+ this.workspaceIndex = new NexusIndex(this, repositoryRegistry.getWorkspaceRepository(), NexusIndex.DETAILS_MIN);
+ }
+
+ private NexusIndex newLocalIndex(IRepository localRepository) {
+ return new NexusIndex(this, localRepository, NexusIndex.DETAILS_FULL);
+ }
+
+ private ArrayList<IndexCreator> getFullCreator() {
+ if(fullCreators == null) {
+ try {
+ PlexusContainer container = MavenPlugin.getDefault().getPlexusContainer();
+ IndexCreator min = container.lookup(IndexCreator.class, MinimalArtifactInfoIndexCreator.ID);
+ IndexCreator mavenPlugin = container.lookup(IndexCreator.class, MavenPluginArtifactInfoIndexCreator.ID);
+ IndexCreator mavenArchetype = container.lookup(IndexCreator.class, MavenArchetypeArtifactInfoIndexCreator.ID);
+ IndexCreator jar = container.lookup(IndexCreator.class, JarFileContentsIndexCreator.ID);
+
+ fullCreators = new ArrayList<IndexCreator>();
+ fullCreators.add(min);
+ fullCreators.add(jar);
+ fullCreators.add(mavenPlugin);
+ fullCreators.add(mavenArchetype);
+ } catch(ComponentLookupException ce) {
+ String msg = "Error looking up component ";
+ console.logError(msg + "; " + ce.getMessage()); //$NON-NLS-1$
+ MavenLogger.log(msg, ce);
+
+ }
+ }
+ return fullCreators;
+ }
+
+ private ArrayList<IndexCreator> getMinCreator() {
+ if(minCreators == null) {
+ try {
+ PlexusContainer container = MavenPlugin.getDefault().getPlexusContainer();
+ IndexCreator min = container.lookup(IndexCreator.class, MinimalArtifactInfoIndexCreator.ID);
+ IndexCreator mavenArchetype = container.lookup(IndexCreator.class, MavenArchetypeArtifactInfoIndexCreator.ID);
+ minCreators = new ArrayList<IndexCreator>();
+ minCreators.add(min);
+ minCreators.add(mavenArchetype);
+ } catch(ComponentLookupException ce) {
+ String msg = "Error looking up component ";
+ MavenLogger.log(msg, ce);
+ }
+
+ }
+ return minCreators;
+ }
+
+ /** for Unit test */
+ public IndexedArtifactFile getIndexedArtifactFile(IRepository repository, ArtifactKey gav) throws CoreException {
+
+ try {
+ BooleanQuery query = new BooleanQuery();
+ query.add(constructQuery(MAVEN.GROUP_ID, gav.getGroupId(), SearchType.EXACT), BooleanClause.Occur.MUST);
+ query.add(constructQuery(MAVEN.ARTIFACT_ID, gav.getArtifactId(), SearchType.EXACT), BooleanClause.Occur.MUST);
+ query.add(constructQuery(MAVEN.VERSION, gav.getVersion(), SearchType.EXACT), BooleanClause.Occur.MUST);
+
+ if(gav.getClassifier() != null) {
+ query.add(constructQuery(MAVEN.CLASSIFIER, gav.getClassifier(), SearchType.EXACT), BooleanClause.Occur.MUST);
+ }
+
+ synchronized(getIndexLock(repository)) {
+ ArtifactInfo artifactInfo = getIndexer().identify(query, Collections.singleton(getIndexingContext(repository)));
+ if(artifactInfo != null) {
+ return getIndexedArtifactFile(artifactInfo);
+ }
+ }
+ } catch(Exception ex) {
+ String msg = "Illegal artifact coordinate " + ex.getMessage();
+ MavenLogger.log(msg, ex);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_search, ex));
+ }
+ return null;
+ }
+
+ /** for Unit test */
+ public IndexedArtifactFile getIndexedArtifactFile(ArtifactInfo artifactInfo) {
+ String groupId = artifactInfo.groupId;
+ String artifactId = artifactInfo.artifactId;
+ String repository = artifactInfo.repository;
+ String version = artifactInfo.version;
+ String classifier = artifactInfo.classifier;
+ String packaging = artifactInfo.packaging;
+ String fname = artifactInfo.fname;
+ if(fname == null) {
+ fname = artifactId + '-' + version
+ + (classifier != null ? '-' + classifier : "") + (packaging != null ? ('.' + packaging) : ""); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ long size = artifactInfo.size;
+ Date date = new Date(artifactInfo.lastModified);
+
+ int sourcesExists = artifactInfo.sourcesExists.ordinal();
+ int javadocExists = artifactInfo.javadocExists.ordinal();
+
+ String prefix = artifactInfo.prefix;
+ List<String> goals = artifactInfo.goals;
+
+ return new IndexedArtifactFile(repository, groupId, artifactId, version, packaging, classifier, fname, size, date,
+ sourcesExists, javadocExists, prefix, goals);
+ }
+
+ public IndexedArtifactFile identify(File file) throws CoreException {
+ try {
+ ArtifactInfo artifactInfo = getIndexer().identify(file);
+ return artifactInfo == null ? null : getIndexedArtifactFile(artifactInfo);
+ } catch(IOException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_search, ex));
+ }
+ }
+
+ protected IndexedArtifactFile identify(IRepository repository, File file) throws CoreException {
+ try {
+ IndexingContext context = getIndexingContext(repository);
+ ArtifactInfo artifactInfo = identify(file, Collections.singleton(context));
+ return artifactInfo == null ? null : getIndexedArtifactFile(artifactInfo);
+ } catch(IOException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_search, ex));
+ }
+ }
+
+ /**
+ * Method to construct Lucene Queries without need to actually know the structure and details (field names, analyze
+ * details, etc) of the underlying index. Also, using this methods makes you "future proof". Naturally, at caller
+ * level you can still combine these queries using BooleanQuery to suit your needs.
+ *
+ * @param field
+ * @param query
+ * @param type
+ * @return
+ */
+ public Query constructQuery(Field field, SearchExpression query) {
+ // let the default be "scored" search
+ SearchType st = SearchType.SCORED;
+
+ if(query instanceof MatchTyped) {
+ MatchType mt = ((MatchTyped) query).getMatchType();
+
+ if(MatchType.EXACT.equals(mt)) {
+ st = SearchType.EXACT;
+ }
+ }
+
+ return constructQuery(field, query.getStringValue(), st);
+ }
+
+ private Query constructQuery(Field field, String query, SearchType searchType) {
+ return getIndexer().constructQuery(field, query, searchType);
+ }
+
+ public Map<String, IndexedArtifact> search(SearchExpression term, String type) throws CoreException {
+ return search(null, term, type, IIndex.SEARCH_ALL);
+ }
+
+ public Map<String, IndexedArtifact> search(SearchExpression term, String type, int classifier) throws CoreException {
+ return search(null, term, type, classifier);
+ }
+
+ private void addClassifiersToQuery(BooleanQuery bq, int classifier) {
+ boolean includeJavaDocs = (classifier & IIndex.SEARCH_JAVADOCS) > 0;
+ Query tq = null;
+ if(!includeJavaDocs) {
+ tq = constructQuery(MAVEN.CLASSIFIER, "javadoc", SearchType.EXACT); //$NON-NLS-1$
+ bq.add(tq, Occur.MUST_NOT);
+ }
+ boolean includeSources = (classifier & IIndex.SEARCH_SOURCES) > 0;
+ if(!includeSources) {
+ tq = constructQuery(MAVEN.CLASSIFIER, "sources", SearchType.EXACT); //$NON-NLS-1$
+ bq.add(tq, Occur.MUST_NOT);
+ }
+ boolean includeTests = (classifier & IIndex.SEARCH_TESTS) > 0;
+ if(!includeTests) {
+ tq = constructQuery(MAVEN.CLASSIFIER, "tests", SearchType.EXACT); //$NON-NLS-1$
+ bq.add(tq, Occur.MUST_NOT);
+ }
+ }
+
+ /**
+ * @return Map<String, IndexedArtifact>
+ */
+ protected Map<String, IndexedArtifact> search(IRepository repository, SearchExpression term, String type,
+ int classifier) throws CoreException {
+ Query query;
+ if(IIndex.SEARCH_GROUP.equals(type)) {
+ query = constructQuery(MAVEN.GROUP_ID, term);
+ // query = new TermQuery(new Term(ArtifactInfo.GROUP_ID, term));
+ // query = new PrefixQuery(new Term(ArtifactInfo.GROUP_ID, term));
+ } else if(IIndex.SEARCH_ARTIFACT.equals(type)) {
+ BooleanQuery bq = new BooleanQuery();
+ bq.add(constructQuery(MAVEN.GROUP_ID, term), Occur.SHOULD); //$NON-NLS-1$
+ bq.add(constructQuery(MAVEN.ARTIFACT_ID, term), Occur.SHOULD); //$NON-NLS-1$
+ bq.add(
+ constructQuery(MAVEN.SHA1, term.getStringValue(), term.getStringValue().length() == 40 ? SearchType.EXACT
+ : SearchType.SCORED), Occur.SHOULD);
+ addClassifiersToQuery(bq, classifier);
+ query = bq;
+
+ } else if(IIndex.SEARCH_PARENTS.equals(type)) {
+ if(term == null) { //$NON-NLS-1$ //$NON-NLS-2$
+ query = constructQuery(MAVEN.PACKAGING, "pom", SearchType.EXACT); //$NON-NLS-1$
+ } else {
+ BooleanQuery bq = new BooleanQuery();
+ bq.add(constructQuery(MAVEN.GROUP_ID, term), Occur.SHOULD); //$NON-NLS-1$
+ bq.add(constructQuery(MAVEN.ARTIFACT_ID, term), Occur.SHOULD); //$NON-NLS-1$
+ bq.add(
+ constructQuery(MAVEN.SHA1, term.getStringValue(), term.getStringValue().length() == 40 ? SearchType.EXACT
+ : SearchType.SCORED), Occur.SHOULD);
+ Query tq = constructQuery(MAVEN.PACKAGING, "pom", SearchType.EXACT); //$NON-NLS-1$
+ query = new FilteredQuery(tq, new QueryWrapperFilter(bq));
+ }
+
+ } else if(IIndex.SEARCH_PLUGIN.equals(type)) {
+ if(term == null) { //$NON-NLS-1$
+ query = constructQuery(MAVEN.PACKAGING, "maven-plugin", SearchType.EXACT); //$NON-NLS-1$
+ } else {
+ BooleanQuery bq = new BooleanQuery();
+ bq.add(constructQuery(MAVEN.GROUP_ID, term), Occur.SHOULD); //$NON-NLS-1$
+ bq.add(constructQuery(MAVEN.ARTIFACT_ID, term), Occur.SHOULD); //$NON-NLS-1$
+ Query tq = constructQuery(MAVEN.PACKAGING, "maven-plugin", SearchType.EXACT); //$NON-NLS-1$
+ query = new FilteredQuery(tq, new QueryWrapperFilter(bq));
+ }
+
+ } else if(IIndex.SEARCH_ARCHETYPE.equals(type)) {
+ BooleanQuery bq = new BooleanQuery();
+ bq.add(constructQuery(MAVEN.GROUP_ID, term), Occur.SHOULD); //$NON-NLS-1$
+ bq.add(constructQuery(MAVEN.ARTIFACT_ID, term), Occur.SHOULD); //$NON-NLS-1$
+ Query tq = constructQuery(MAVEN.PACKAGING, "maven-archetype", SearchType.EXACT); //$NON-NLS-1$
+ query = new FilteredQuery(tq, new QueryWrapperFilter(bq));
+
+ } else if(IIndex.SEARCH_PACKAGING.equals(type)) {
+ query = constructQuery(MAVEN.PACKAGING, term);
+ } else if(IIndex.SEARCH_SHA1.equals(type)) {
+ // if hash is 40 chars, it is "complete", otherwise assume prefix
+ query = constructQuery(MAVEN.SHA1, term.getStringValue(), term.getStringValue().length() == 40 ? SearchType.EXACT
+ : SearchType.SCORED);
+ } else {
+ return Collections.emptyMap();
+ }
+
+ Map<String, IndexedArtifact> result = new TreeMap<String, IndexedArtifact>();
+
+ try {
+ IteratorSearchResponse response;
+
+ synchronized(getIndexLock(repository)) {
+ IndexingContext context = getIndexingContext(repository);
+ if(context == null) {
+ response = getIndexer().searchIterator(new IteratorSearchRequest(query));
+ } else {
+ response = getIndexer().searchIterator(new IteratorSearchRequest(query, context));
+ }
+
+ for(ArtifactInfo artifactInfo : response.getResults()) {
+ addArtifactFile(result, getIndexedArtifactFile(artifactInfo), null, null, artifactInfo.packaging);
+ }
+
+ // https://issues.sonatype.org/browse/MNGECLIPSE-1630
+ // lucene can't handle prefix queries that match many index entries.
+ // to workaround, use term query to locate group artifacts and manually
+ // match subgroups
+ if(IIndex.SEARCH_GROUP.equals(type) && context != null) {
+ Set<String> groups = context.getAllGroups();
+ for(String group : groups) {
+ if(term == null || group.startsWith(term.getStringValue()) && !group.equals(term.getStringValue())) {
+ String key = getArtifactFileKey(group, group, null, null);
+ result.put(key, new IndexedArtifact(group, group, null, null, null));
+ }
+ }
+ }
+ }
+ } catch(IOException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_search, ex));
+ }
+
+ return result;
+ }
+
+ /**
+ * @return Map<String, IndexedArtifact>
+ */
+ protected Map<String, IndexedArtifact> search(IRepository repository, SearchExpression term, String type)
+ throws CoreException {
+ return search(repository, term, type, IIndex.SEARCH_ALL);
+ }
+
+ /**
+ * @return Map<String, IndexedArtifact>
+ */
+ protected Map<String, IndexedArtifact> search(IRepository repository, Query query) throws CoreException {
+ Map<String, IndexedArtifact> result = new TreeMap<String, IndexedArtifact>();
+ try {
+ IteratorSearchResponse response;
+
+ synchronized(getIndexLock(repository)) {
+ IndexingContext context = getIndexingContext(repository);
+ if(context == null) {
+ response = getIndexer().searchIterator(new IteratorSearchRequest(query));
+ } else {
+ response = getIndexer().searchIterator(new IteratorSearchRequest(query, context));
+ }
+ }
+
+ for(ArtifactInfo artifactInfo : response.getResults()) {
+ IndexedArtifactFile af = getIndexedArtifactFile(artifactInfo);
+ addArtifactFile(result, af, null, null, artifactInfo.packaging);
+ }
+
+ } catch(IOException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_search, ex));
+ }
+ return result;
+ }
+
+ private void addArtifactFile(Map<String, IndexedArtifact> result, IndexedArtifactFile af, String className,
+ String packageName, String packaging) {
+ String group = af.group;
+ String artifact = af.artifact;
+ String key = getArtifactFileKey(group, artifact, packageName, className);
+ IndexedArtifact indexedArtifact = result.get(key);
+ if(indexedArtifact == null) {
+ indexedArtifact = new IndexedArtifact(group, artifact, packageName, className, packaging);
+ result.put(key, indexedArtifact);
+ }
+ indexedArtifact.addFile(af);
+ }
+
+ protected String getArtifactFileKey(String group, String artifact, String packageName, String className) {
+ return className + " : " + packageName + " : " + group + " : " + artifact; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ private void purgeCurrentIndex(IndexingContext context) throws IOException {
+ context.purge();
+ }
+
+ private void reindexLocalRepository(IRepository repository, boolean force, final IProgressMonitor monitor)
+ throws CoreException {
+ try {
+ fireIndexUpdating(repository);
+ //IndexInfo indexInfo = getIndexInfo(indexName);
+ IndexingContext context = getIndexingContext(repository);
+ if(force) {
+ purgeCurrentIndex(context);
+ }
+ if(context.getRepository().isDirectory()) {
+ getIndexer().scan(context, new ArtifactScanningMonitor(context.getRepository(), monitor, console), false);
+ }
+ fireIndexChanged(repository);
+ console.logMessage("Updated local repository index");
+ } catch(Exception ex) {
+ MavenLogger.log("Unable to re-index " + repository.toString(), ex);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_reindexing, ex));
+ } finally {
+ fireIndexChanged(repository);
+ }
+ }
+
+ private void reindexWorkspace(boolean force, IProgressMonitor monitor) throws CoreException {
+ IRepository workspaceRepository = repositoryRegistry.getWorkspaceRepository();
+ try {
+ IndexingContext context = getIndexingContext(workspaceRepository);
+ if(force) {
+ purgeCurrentIndex(context);
+ }
+ for(IMavenProjectFacade facade : projectManager.getProjects()) {
+ addDocument(workspaceRepository, facade.getPomFile(), //
+ facade.getArtifactKey());
+ }
+ } catch(Exception ex) {
+ MavenLogger.log("Unable to re-index " + workspaceRepository.toString(), ex);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_reindexing, ex));
+ } finally {
+ fireIndexChanged(workspaceRepository);
+ }
+ }
+
+ protected void addDocument(IRepository repository, File file, ArtifactKey key) {
+ synchronized(getIndexLock(repository)) {
+ IndexingContext context = getIndexingContext(repository);
+ if(context == null) {
+ // TODO log
+ return;
+ }
+ try {
+ ArtifactContext artifactContext;
+ if(repository.isScope(IRepositoryRegistry.SCOPE_WORKSPACE)) {
+ IMavenProjectFacade facade = getProjectByArtifactKey(key);
+ artifactContext = getWorkspaceArtifactContext(facade, context);
+ } else {
+ artifactContext = getArtifactContext(file, context);
+ }
+ getIndexer().addArtifactToIndex(artifactContext, context);
+ } catch(Exception ex) {
+ String msg = "Unable to add " + getDocumentKey(key);
+ console.logError(msg + "; " + ex.getMessage()); //$NON-NLS-1$
+ MavenLogger.log(msg, ex);
+ }
+ }
+ }
+
+ private IMavenProjectFacade getProjectByArtifactKey(ArtifactKey artifactKey) throws CoreException {
+ for(IMavenProjectFacade facade : projectManager.getProjects()) {
+ if(facade.getArtifactKey().equals(artifactKey)) {
+ return facade;
+ }
+ }
+
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_unexpected, new IllegalArgumentException(String.format(
+ "Workspace project with key %s not found!", new Object[] {artifactKey})))); //$NON-NLS-1$
+ }
+
+ protected void removeDocument(IRepository repository, File file, ArtifactKey key, IMavenProjectFacade facade) {
+ synchronized(getIndexLock(repository)) {
+ try {
+ IndexingContext context = getIndexingContext(repository);
+ if(context == null) {
+ String msg = "Unable to find document to remove" + getDocumentKey(key);
+ MavenLogger.log(new Status(IStatus.ERROR, "org.eclipse.m2e", msg)); //$NON-NLS-1$
+ return;
+ }
+ ArtifactContext artifactContext;
+ if(repository.isScope(IRepositoryRegistry.SCOPE_WORKSPACE)) {
+ if(facade == null) {
+ // try to get one, but you MUST have facade in case of project deletion, see mavenProjectChanged()
+ facade = getProjectByArtifactKey(key);
+ }
+ artifactContext = getWorkspaceArtifactContext(facade, context);
+ } else {
+ artifactContext = getArtifactContext(file, context);
+ }
+ getIndexer().deleteArtifactFromIndex(artifactContext, context);
+ } catch(Exception ex) {
+ String msg = "Unable to remove " + getDocumentKey(key);
+ console.logError(msg + "; " + ex.getMessage()); //$NON-NLS-1$
+ MavenLogger.log(msg, ex);
+ }
+ }
+
+ fireIndexChanged(repository);
+ }
+
+ private ArtifactContext getArtifactContext(File file, IndexingContext context)
+ throws IllegalArtifactCoordinateException {
+ return getArtifactContextProducer().getArtifactContext(context, file);
+ }
+
+ private ArtifactContext getWorkspaceArtifactContext(IMavenProjectFacade facade, IndexingContext context)
+ throws CoreException {
+ IRepository workspaceRepository = repositoryRegistry.getWorkspaceRepository();
+ ArtifactKey key = facade.getArtifactKey();
+ ArtifactInfo ai = new ArtifactInfo(workspaceRepository.getUid(), key.getGroupId(), key.getArtifactId(),
+ key.getVersion(), null);
+ ai.packaging = facade.getPackaging();
+ File pomFile = facade.getPomFile();
+ File artifactFile = (pomFile != null) ? pomFile.getParentFile() : null;
+ try {
+ Gav gav = new Gav(key.getGroupId(), key.getArtifactId(), key.getVersion());
+ return new ArtifactContext(pomFile, artifactFile, null, ai, gav);
+ } catch(IllegalArtifactCoordinateException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_unexpected, ex));
+ }
+ }
+
+ protected void scheduleIndexUpdate(final IRepository repository, final boolean force) {
+ if(repository != null) {
+ IndexCommand command = new IndexUpdaterJob.IndexCommand() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ updateIndex(repository, force, monitor);
+ }
+ };
+ updaterJob.addCommand(command);
+ updaterJob.schedule(1000L);
+ }
+ }
+
+ protected Set<String> getRootGroups(IRepository repository) throws CoreException {
+ synchronized(getIndexLock(repository)) {
+ IndexingContext context = getIndexingContext(repository);
+ if(context != null) {
+ try {
+ Set<String> rootGroups = context.getRootGroups();
+ return rootGroups;
+ } catch(IOException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, //
+ NLS.bind(Messages.NexusIndexManager_error_root_grp, repository.toString()), ex));
+ }
+ }
+ return Collections.emptySet();
+ }
+ }
+
+ /** for unit tests */
+ public IndexedArtifactGroup[] getRootIndexedArtifactGroups(IRepository repository) throws CoreException {
+ synchronized(getIndexLock(repository)) {
+ IndexingContext context = getIndexingContext(repository);
+ if(context != null) {
+ try {
+ Set<String> rootGroups = context.getRootGroups();
+ IndexedArtifactGroup[] groups = new IndexedArtifactGroup[rootGroups.size()];
+ int i = 0;
+ for(String group : rootGroups) {
+ groups[i++ ] = new IndexedArtifactGroup(repository, group);
+ }
+ return groups;
+ } catch(IOException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, //
+ NLS.bind(Messages.NexusIndexManager_error_root_grp, repository.toString()), ex));
+ }
+ }
+ return new IndexedArtifactGroup[0];
+ }
+ }
+
+ /** public for unit tests only! */
+ public IndexingContext getIndexingContext(IRepository repository) {
+ return repository == null ? null : getIndexer().getIndexingContexts().get(repository.getUid());
+ }
+
+ private NexusIndexer getIndexer() {
+ synchronized(indexerLock) {
+ if(indexer == null) {
+ indexer = MavenPlugin.getDefault().getNexusIndexer();
+ }
+ }
+ return indexer;
+ }
+
+ private ArtifactContextProducer getArtifactContextProducer() {
+ synchronized(contextProducerLock) {
+ if(artifactContextProducer == null) {
+ artifactContextProducer = MavenPlugin.getDefault().getArtifactContextProducer();
+ }
+ }
+ return artifactContextProducer;
+ }
+
+ public static String getDocumentKey(ArtifactKey artifact) {
+ String groupId = artifact.getGroupId();
+ if(groupId == null) {
+ groupId = Messages.NexusIndexManager_inherited;
+ }
+
+ String artifactId = artifact.getArtifactId();
+
+ String version = artifact.getVersion();
+ if(version == null) {
+ version = Messages.NexusIndexManager_inherited;
+ }
+
+ String key = groupId.replace('.', '/') + '/' + artifactId + '/' + version + '/' + artifactId + "-" + version; //$NON-NLS-1$
+
+ String classifier = artifact.getClassifier();
+ if(classifier != null) {
+ key += "-" + classifier; //$NON-NLS-1$
+ }
+
+ // TODO use artifact handler to retrieve extension
+ // cstamas: will not work since ArtifactKey misses type
+ // either get packaging from POM or store/honor extension
+ return key + ".pom"; //$NON-NLS-1$
+ }
+
+ public void mavenProjectChanged(MavenProjectChangedEvent[] events, IProgressMonitor monitor) {
+ /*
+ * This method is called while holding workspace lock. Avoid long-running operations if possible.
+ */
+
+ synchronized(getIndexLock(repositoryRegistry.getWorkspaceRepository())) {
+ IndexingContext context = getIndexingContext(repositoryRegistry.getWorkspaceRepository());
+
+ if(context != null) {
+ // workspace indexing context can by null during startup due to MNGECLIPSE-1633
+ for(MavenProjectChangedEvent event : events) {
+ IMavenProjectFacade oldFacade = event.getOldMavenProject();
+ if(oldFacade != null) {
+ removeDocument(repositoryRegistry.getWorkspaceRepository(), oldFacade.getPomFile(),
+ oldFacade.getArtifactKey(), oldFacade);
+ fireIndexRemoved(repositoryRegistry.getWorkspaceRepository());
+ }
+ IMavenProjectFacade facade = event.getMavenProject();
+ if(facade != null) {
+ addDocument(repositoryRegistry.getWorkspaceRepository(), facade.getPomFile(), facade.getArtifactKey());
+ fireIndexAdded(repositoryRegistry.getWorkspaceRepository());
+ }
+ }
+ }
+ }
+ }
+
+ public NexusIndex getWorkspaceIndex() {
+ return workspaceIndex;
+ }
+
+ public NexusIndex getLocalIndex() {
+ IRepository localRepository = repositoryRegistry.getLocalRepository();
+ synchronized(getIndexLock(localRepository)) {
+ if(localIndex == null) {
+ localIndex = newLocalIndex(localRepository);
+ }
+ }
+ return localIndex;
+ }
+
+ public IIndex getIndex(IProject project) {
+ IMavenProjectFacade projectFacade = project != null ? projectManager.getProject(project) : null;
+
+ ArrayList<IIndex> indexes = new ArrayList<IIndex>();
+ indexes.add(getWorkspaceIndex());
+ indexes.add(getLocalIndex());
+
+ if(projectFacade != null) {
+ LinkedHashSet<ArtifactRepositoryRef> repositories = new LinkedHashSet<ArtifactRepositoryRef>();
+ repositories.addAll(projectFacade.getArtifactRepositoryRefs());
+ repositories.addAll(projectFacade.getPluginArtifactRepositoryRefs());
+
+ for(ArtifactRepositoryRef repositoryRef : repositories) {
+ IRepository repository = repositoryRegistry.getRepository(repositoryRef);
+ indexes.add(getIndex(repository));
+ }
+ } else {
+ for(IRepository repository : repositoryRegistry.getRepositories(IRepositoryRegistry.SCOPE_SETTINGS)) {
+ indexes.add(getIndex(repository));
+ }
+ }
+
+ return new CompositeIndex(indexes);
+ }
+
+ public IIndex getAllIndexes() {
+ ArrayList<IIndex> indexes = new ArrayList<IIndex>();
+ indexes.add(getWorkspaceIndex());
+ indexes.add(getLocalIndex());
+
+ for(IMavenProjectFacade facade : projectManager.getProjects()) {
+ LinkedHashSet<ArtifactRepositoryRef> repositories = new LinkedHashSet<ArtifactRepositoryRef>();
+ repositories.addAll(facade.getArtifactRepositoryRefs());
+ repositories.addAll(facade.getPluginArtifactRepositoryRefs());
+
+ for(ArtifactRepositoryRef repositoryRef : repositories) {
+ IRepository repository = repositoryRegistry.getRepository(repositoryRef);
+ indexes.add(getIndex(repository));
+ }
+ }
+
+ return new CompositeIndex(indexes);
+ }
+
+ public NexusIndex getIndex(IRepository repository) {
+ String details = getIndexDetails(repository);
+ return new NexusIndex(this, repository, details);
+ }
+
+ protected File getIndexDirectoryFile(IRepository repository) {
+ return new File(baseIndexDir, repository.getUid());
+ }
+
+ protected Directory getIndexDirectory(IRepository repository) throws IOException {
+ return FSDirectory.getDirectory(getIndexDirectoryFile(repository));
+ }
+
+ public IndexedArtifactGroup resolveGroup(IndexedArtifactGroup group) {
+ IRepository repository = group.getRepository();
+ String prefix = group.getPrefix();
+ try {
+ IndexedArtifactGroup g = new IndexedArtifactGroup(repository, prefix);
+ for(IndexedArtifact a : search(repository, new SourcedSearchExpression(prefix), IIndex.SEARCH_GROUP).values()) {
+ String groupId = a.getGroupId();
+ if(groupId.equals(prefix)) {
+ g.getFiles().put(a.getArtifactId(), a);
+ } else if(groupId.startsWith(prefix + ".")) { //$NON-NLS-1$
+ int start = prefix.length() + 1;
+ int end = groupId.indexOf('.', start);
+ String key = end > -1 ? groupId.substring(0, end) : groupId;
+ g.getNodes().put(key, new IndexedArtifactGroup(repository, key));
+ }
+ }
+
+ return g;
+
+ } catch(CoreException ex) {
+ MavenLogger.log("Can't retrieve groups for " + repository.toString() + ":" + prefix, ex); //$NON-NLS-2$
+ return group;
+ }
+ }
+
+ public void repositoryAdded(IRepository repository, IProgressMonitor monitor) throws CoreException {
+ String details = getIndexDetails(repository);
+
+ // for consistency, always process indexes using our background thread
+ setIndexDetails(repository, null, details, null/*async*/);
+ }
+
+ /** For tests only */
+ public String getIndexDetails(IRepository repository) {
+ String details = indexDetails.getProperty(repository.getUid());
+
+ if(details == null) {
+ if(repository.isScope(IRepositoryRegistry.SCOPE_SETTINGS) && repository.getMirrorId() == null) {
+ details = NexusIndex.DETAILS_MIN;
+ } else if(repository.isScope(IRepositoryRegistry.SCOPE_LOCAL)) {
+ details = NexusIndex.DETAILS_MIN;
+ } else if(repository.isScope(IRepositoryRegistry.SCOPE_WORKSPACE)) {
+ details = NexusIndex.DETAILS_MIN;
+ } else {
+ details = NexusIndex.DETAILS_DISABLED;
+ }
+ }
+
+ return details;
+ }
+
+ /**
+ * Updates index synchronously if monitor!=null. Schedules index update otherwise. ... and yes, I know this ain't
+ * kosher. Public for unit tests only!
+ */
+ public void setIndexDetails(IRepository repository, String details, IProgressMonitor monitor) throws CoreException {
+ setIndexDetails(repository, details, details, monitor);
+ }
+
+ private void setIndexDetails(IRepository repository, String details, String defaultDetails, IProgressMonitor monitor)
+ throws CoreException {
+ if(details != null) {
+ indexDetails.setProperty(repository.getUid(), details);
+
+ writeIndexDetails();
+ } else {
+ details = defaultDetails;
+ }
+
+ synchronized(getIndexLock(repository)) {
+ IndexingContext indexingContext = getIndexingContext(repository);
+
+ try {
+ if(NexusIndex.DETAILS_DISABLED.equals(details)) {
+ if(indexingContext != null) {
+ getIndexer().removeIndexingContext(indexingContext, false /*removeFiles*/);
+ fireIndexRemoved(repository);
+ }
+ } else {
+ if(indexingContext != null) {
+ getIndexer().removeIndexingContext(indexingContext, false);
+ }
+
+ createIndexingContext(repository, details);
+
+ fireIndexAdded(repository);
+
+ if(monitor != null) {
+ updateIndex(repository, false, monitor);
+ } else {
+ scheduleIndexUpdate(repository, false);
+ }
+ }
+ } catch(IOException ex) {
+ String msg = "Error changing index details " + repository.toString();
+ console.logError(msg + "; " + ex.getMessage()); //$NON-NLS-1$
+ MavenLogger.log(msg, ex);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_add_repo, ex));
+ }
+
+ if(repository.isScope(IRepositoryRegistry.SCOPE_LOCAL)) {
+ // note that we are still synchronized on repository lock at this point
+ this.localIndex = newLocalIndex(repositoryRegistry.getLocalRepository());
+ }
+ }
+ }
+
+ protected IndexingContext createIndexingContext(IRepository repository, String details) throws IOException {
+ IndexingContext indexingContext;
+ Directory directory = getIndexDirectory(repository);
+
+ File repositoryPath = null;
+ if(repository.getBasedir() != null) {
+ repositoryPath = repository.getBasedir().getCanonicalFile();
+ }
+
+ ArrayList<IndexCreator> indexers = getIndexers(details);
+
+ indexingContext = getIndexer().addIndexingContextForced(repository.getUid(), //
+ repository.getUrl(), //
+ repositoryPath, //
+ directory, //
+ repository.getUrl(), null, //
+ indexers);
+
+ indexingContext.setSearchable(false);
+
+ return indexingContext;
+ }
+
+ protected ArrayList<IndexCreator> getIndexers(String details) {
+ boolean fullIndex = NexusIndex.DETAILS_FULL.equals(details);
+ ArrayList<IndexCreator> indexers = fullIndex ? getFullCreator() : getMinCreator();
+ return indexers;
+ }
+
+ public void repositoryRemoved(IRepository repository, IProgressMonitor monitor) {
+ synchronized(getIndexLock(repository)) {
+ try {
+ IndexingContext context = getIndexingContext(repository);
+ if(context == null) {
+ return;
+ }
+ getIndexer().removeIndexingContext(context, false);
+ } catch(IOException ie) {
+ String msg = "Unable to delete files for index";
+ MavenLogger.log(msg, ie);
+ }
+ }
+
+ fireIndexRemoved(repository);
+ }
+
+ protected void fireIndexAdded(IRepository repository) {
+ synchronized(indexListeners) {
+ for(IndexListener listener : indexListeners) {
+ listener.indexAdded(repository);
+ }
+ }
+ }
+
+ protected void fireIndexRemoved(IRepository repository) {
+ synchronized(updatingIndexes) {
+ if(repository != null) {
+ //since workspace index can be null at startup, guard against nulls
+ updatingIndexes.remove(repository.getUid());
+ }
+ }
+ synchronized(indexListeners) {
+ for(IndexListener listener : indexListeners) {
+ listener.indexRemoved(repository);
+ }
+ }
+ }
+
+ protected boolean isUpdatingIndex(IRepository repository) {
+ synchronized(updatingIndexes) {
+ return updatingIndexes.contains(repository.getUid());
+ }
+ }
+
+ protected void fireIndexUpdating(IRepository repository) {
+ synchronized(updatingIndexes) {
+ if(repository != null) {
+ //since workspace index can be null at startup, guard against nulls
+ updatingIndexes.add(repository.getUid());
+ }
+ }
+ synchronized(indexListeners) {
+ for(IndexListener listener : indexListeners) {
+ listener.indexUpdating(repository);
+ }
+ }
+ }
+
+ protected void fireIndexChanged(IRepository repository) {
+ synchronized(updatingIndexes) {
+ if(repository != null) {
+ //since workspace index can be null at startup, guard against nulls
+ updatingIndexes.remove(repository.getUid());
+ }
+
+ }
+ synchronized(indexListeners) {
+ for(IndexListener listener : indexListeners) {
+ listener.indexChanged(repository);
+ }
+ }
+ }
+
+ public void removeIndexListener(IndexListener listener) {
+ synchronized(indexListeners) {
+ indexListeners.remove(listener);
+ }
+ }
+
+ public void addIndexListener(IndexListener listener) {
+ synchronized(indexListeners) {
+ if(!indexListeners.contains(listener)) {
+ indexListeners.add(listener);
+ }
+ }
+ }
+
+ //Public for testing purpose.
+ public void updateIndex(IRepository repository, boolean force, IProgressMonitor monitor) throws CoreException {
+ synchronized(getIndexLock(repository)) {
+ if(repository.isScope(IRepositoryRegistry.SCOPE_WORKSPACE)) {
+ reindexWorkspace(force, monitor);
+ } else {
+ IndexingContext context = getIndexingContext(repository);
+ if(context != null) {
+ if(context.getRepository() != null) {
+ reindexLocalRepository(repository, force, monitor);
+ } else {
+ if(!force) {
+ //if 'force' is not set, then only do the remote update if this value is set
+ IMavenConfiguration mavenConfig = MavenPlugin.getDefault().getMavenConfiguration();
+ if(mavenConfig.isUpdateIndexesOnStartup()) {
+ updateRemoteIndex(repository, force, monitor);
+ }
+ } else {
+ updateRemoteIndex(repository, force, monitor);
+ }
+ }
+ }
+ }
+ IndexingContext context = getIndexingContext(repository);
+ if(context != null) {
+ context.setSearchable(true);
+ }
+ }
+ }
+
+ /*
+ * Callers must hold repository access synchronisation lock
+ */
+ private void updateRemoteIndex(IRepository repository, boolean force, IProgressMonitor monitor) {
+ if(repository == null) {
+ return;
+ }
+
+ if(monitor != null) {
+ monitor.setTaskName(NLS.bind(Messages.NexusIndexManager_task_updating, repository.toString()));
+ }
+ console.logMessage("Updating index " + repository.toString());
+ try {
+ fireIndexUpdating(repository);
+
+ IndexingContext context = getIndexingContext(repository);
+
+ if(context != null) {
+ IndexUpdateRequest request = newIndexUpdateRequest(repository, context, monitor);
+ request.setForceFullUpdate(force);
+
+ Lock cacheLock = locker.lock(request.getLocalIndexCacheDir());
+ try {
+ boolean updated;
+
+ request.setCacheOnly(true);
+ IndexUpdateResult result = indexUpdater.fetchAndUpdateIndex(request);
+ if(result.isFullUpdate() || !context.isSearchable()) {
+ // need to fully recreate index
+
+ // 1. process index gz into cached/shared lucene index. this can be a noop if cache is uptodate
+ String details = getIndexDetails(repository);
+ String id = repository.getUid() + "-cache"; //$NON-NLS-1$
+ File luceneCache = new File(request.getLocalIndexCacheDir(), details);
+ Directory directory = FSDirectory.getDirectory(luceneCache);
+ IndexingContext cacheCtx = getIndexer().addIndexingContextForced(id, id, null, directory, null, null,
+ getIndexers(details));
+ request = newIndexUpdateRequest(repository, cacheCtx, monitor);
+ request.setOffline(true);
+ indexUpdater.fetchAndUpdateIndex(request);
+
+ // 2. copy cached/shared (this is not very elegant, oh well)
+ getIndexer().removeIndexingContext(context, true); // nuke workspace index files
+ getIndexer().removeIndexingContext(cacheCtx, false); // keep the cache!
+ FileUtils.cleanDirectory(context.getIndexDirectoryFile());
+ FileUtils.copyDirectory(luceneCache, context.getIndexDirectoryFile()); // copy cached lucene index
+ context = createIndexingContext(repository, details); // re-create indexing context
+
+ updated = true;
+ } else {
+ // incremental change
+ request = newIndexUpdateRequest(repository, context, monitor);
+ request.setOffline(true); // local cache is already uptodate, no need to
+ result = indexUpdater.fetchAndUpdateIndex(request);
+ updated = result.getTimestamp() != null;
+ }
+
+ if(updated) {
+ console.logMessage("Updated index for " + repository.toString());
+ } else {
+ console.logMessage("No index update available for " + repository.toString());
+ }
+
+ } finally {
+ cacheLock.release();
+ }
+ }
+ } catch(FileNotFoundException e) {
+ String msg = "Unable to update index for " + repository.toString() + ": " + e.getMessage(); //$NON-NLS-2$
+ console.logError(msg);
+ } catch(Exception ie) {
+ String msg = "Unable to update index for " + repository.toString();
+ MavenLogger.log(msg, ie);
+ console.logError(msg);
+ } finally {
+ fireIndexChanged(repository);
+ }
+ }
+
+ protected IndexUpdateRequest newIndexUpdateRequest(IRepository repository, IndexingContext context,
+ IProgressMonitor monitor) throws IOException, CoreException {
+ ProxyInfo proxyInfo = maven.getProxyInfo(repository.getProtocol());
+ AuthenticationInfo authenticationInfo = repository.getAuthenticationInfo();
+
+ IndexUpdateRequest request = new IndexUpdateRequest(context, new AsyncFetcher(authenticationInfo, proxyInfo,
+ monitor));
+ File localRepo = repositoryRegistry.getLocalRepository().getBasedir();
+ File indexCacheBasedir = new File(localRepo, ".cache/m2e/" + MavenPlugin.getVersion()).getCanonicalFile(); //$NON-NLS-1$
+ File indexCacheDir = new File(indexCacheBasedir, repository.getUid());
+ indexCacheDir.mkdirs();
+ request.setLocalIndexCacheDir(indexCacheDir);
+ return request;
+ }
+
+ public void initialize(IProgressMonitor monitor) throws CoreException {
+ try {
+ BufferedInputStream is = new BufferedInputStream(new FileInputStream(getIndexDetailsFile()));
+ try {
+ indexDetails.load(is);
+ } finally {
+ is.close();
+ }
+ } catch(FileNotFoundException e) {
+ // that's quite alright
+ } catch(IOException e) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_read_index, e));
+ }
+ }
+
+ protected void writeIndexDetails() throws CoreException {
+ try {
+ File indexDetailsFile = getIndexDetailsFile();
+ indexDetailsFile.getParentFile().mkdirs();
+ BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(indexDetailsFile));
+ try {
+ indexDetails.store(os, null);
+ } finally {
+ os.close();
+ }
+ } catch(IOException e) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.NexusIndexManager_error_write_index, e));
+ }
+ }
+
+ private File getIndexDetailsFile() {
+ return new File(baseIndexDir, "indexDetails.properties"); //$NON-NLS-1$
+ }
+
+ /** for unit tests only */
+ public Job getIndexUpdateJob() {
+ return updaterJob;
+ }
+
+ public String getIndexerId() {
+ return Messages.NexusIndexManager_78;
+ }
+
+ private Object getIndexLock(IRepository repository) {
+ if(repository == null) {
+ return new Object();
+ }
+ // NOTE: We ultimately want to prevent concurrent access to the IndexingContext so we sync on the repo UID and not on the repo instance.
+ synchronized(indexLocks) {
+ Object lock = indexLocks.get(repository.getUid());
+ if(lock == null) {
+ lock = new Object();
+ indexLocks.put(repository.getUid(), lock);
+ }
+ return lock;
+ }
+ }
+
+ /// REMOVE THIS BELOW ONCE Maven Indexer upgraded to 3.2.0-SNAPSHOT
+ /// In that moment this code becomes duplicated and already in place, this method added
+
+ protected ArtifactInfo identify(File artifact, Collection<IndexingContext> contexts) throws IOException {
+
+ FileInputStream is = null;
+
+ try {
+ MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
+
+ is = new FileInputStream(artifact);
+
+ byte[] buff = new byte[4096];
+
+ int n;
+
+ while((n = is.read(buff)) > -1) {
+ sha1.update(buff, 0, n);
+ }
+
+ byte[] digest = sha1.digest();
+
+ Query q = getIndexer().constructQuery(MAVEN.SHA1, encode(digest), SearchType.EXACT);
+
+ return getIndexer().identify(q, contexts);
+
+ } catch(NoSuchAlgorithmException ex) {
+ throw new IOException("Unable to calculate digest");
+ } finally {
+ IOUtil.close(is);
+ }
+
+ }
+
+ private static final char[] DIGITS = "0123456789abcdef".toCharArray();
+
+ private static String encode(byte[] digest) {
+ char[] buff = new char[digest.length * 2];
+
+ int n = 0;
+
+ for(byte b : digest) {
+ buff[n++ ] = DIGITS[(0xF0 & b) >> 4];
+ buff[n++ ] = DIGITS[0x0F & b];
+ }
+
+ return new String(buff);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecycle/LifecycleMappingFactory.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecycle/LifecycleMappingFactory.java
new file mode 100644
index 00000000..78c43fe7
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecycle/LifecycleMappingFactory.java
@@ -0,0 +1,238 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.lifecycle;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+
+import org.apache.maven.plugin.MojoExecution;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.project.IgnoreMojoProjectConfiguration;
+import org.eclipse.m2e.core.internal.project.MojoExecutionProjectConfigurator;
+import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator;
+import org.eclipse.m2e.core.project.configurator.CustomizableLifecycleMapping;
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+import org.eclipse.m2e.core.project.configurator.PluginExecutionFilter;
+
+
+/**
+ * LifecycleMappingFactory
+ *
+ * @author igor
+ */
+public class LifecycleMappingFactory {
+
+ public static final String EXTENSION_LIFECYCLE_MAPPINGS = IMavenConstants.PLUGIN_ID + ".lifecycleMappings"; //$NON-NLS-1$
+
+ public static final String EXTENSION_PROJECT_CONFIGURATORS = IMavenConstants.PLUGIN_ID + ".projectConfigurators"; //$NON-NLS-1$
+
+ private static final String ELEMENT_LIFECYCLE_MAPPING = "lifecycleMapping"; //$NON-NLS-1$
+
+ private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
+
+ private static final String ATTR_PACKAGING_TYPE = "packaging-type"; //$NON-NLS-1$
+
+ private static final String ATTR_ID = "id"; //$NON-NLS-1$
+
+ private static final String ELEMENT_CONFIGURATOR = "configurator"; //$NON-NLS-1$
+
+ private static final String ELEMENT_MOJO = "mojo"; //$NON-NLS-1$
+
+ private static final String ELEMENT_IGNORE = "ignore"; //$NON-NLS-1$
+
+ private static final String ELEMENT_EXECUTE = "execute";
+
+ private static final String ATTR_GROUPID = "groupId";
+
+ private static final String ATTR_ARTIFACTID = "artifactId";
+
+ private static final String ATTR_VERSIONRANGE = "versionRange";
+
+ private static final String ATTR_GOALS = "goals";
+
+ /**
+ * Returns default lifecycle mapping for specified packaging type or null if no such lifecycle mapping
+ */
+ public static ILifecycleMapping getLifecycleMappingFor(String packagingType) {
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint configuratorsExtensionPoint = registry.getExtensionPoint(EXTENSION_LIFECYCLE_MAPPINGS);
+ if(configuratorsExtensionPoint != null) {
+ IExtension[] configuratorExtensions = configuratorsExtensionPoint.getExtensions();
+ for(IExtension extension : configuratorExtensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for(IConfigurationElement element : elements) {
+ if(element.getName().equals(ELEMENT_LIFECYCLE_MAPPING)) {
+ if(packagingType.equals(element.getAttribute(ATTR_PACKAGING_TYPE))) {
+ return createLifecycleMapping(element);
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ protected static ILifecycleMapping createLifecycleMapping(IConfigurationElement element) {
+ try {
+ ILifecycleMapping mapping = (ILifecycleMapping) element.createExecutableExtension(ATTR_CLASS);
+ if(mapping instanceof CustomizableLifecycleMapping) {
+ CustomizableLifecycleMapping customizable = (CustomizableLifecycleMapping) mapping;
+ for(IConfigurationElement mojo : element.getChildren(ELEMENT_MOJO)) {
+ AbstractProjectConfigurator configurator = null;
+ if(mojo.getChildren(ELEMENT_IGNORE).length > 0) {
+ configurator = new IgnoreMojoProjectConfiguration();
+ } else if(mojo.getChildren(ELEMENT_EXECUTE).length > 0) {
+ configurator = createMojoExecution(mojo.getChildren(ELEMENT_EXECUTE)[0]);
+ } else if(mojo.getChildren(ELEMENT_CONFIGURATOR).length > 0) {
+ String configuratorId = mojo.getChildren(ELEMENT_CONFIGURATOR)[0].getAttribute(ATTR_ID);
+ configurator = createProjectConfigurator(configuratorId, true/*bare*/);
+ } else {
+ MavenLogger.log("Invalid lifecycle mapping configuration element: " + mojo.toString());
+ }
+ if(configurator != null) {
+ configurator.addPluginExecutionFilter(createPluginExecutionFilter(mojo));
+ customizable.addConfigurator(configurator);
+ }
+ }
+ }
+ return mapping;
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ return null;
+ }
+
+ private static AbstractProjectConfigurator createMojoExecution(IConfigurationElement configuration) {
+ boolean runOnIncremental = true; // TODO
+ return new MojoExecutionProjectConfigurator(runOnIncremental);
+ }
+
+ private static PluginExecutionFilter createPluginExecutionFilter(IConfigurationElement configuration) {
+ String groupId = configuration.getAttribute(ATTR_GROUPID);
+ String artifactId = configuration.getAttribute(ATTR_ARTIFACTID);
+ String versionRange = configuration.getAttribute(ATTR_VERSIONRANGE);
+ String goals = configuration.getAttribute(ATTR_GOALS);
+ return new PluginExecutionFilter(groupId, artifactId, versionRange, goals);
+ }
+
+ public static ILifecycleMapping getLifecycleMapping(String mappingId) {
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint configuratorsExtensionPoint = registry.getExtensionPoint(EXTENSION_LIFECYCLE_MAPPINGS);
+ if(configuratorsExtensionPoint != null) {
+ IExtension[] configuratorExtensions = configuratorsExtensionPoint.getExtensions();
+ for(IExtension extension : configuratorExtensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for(IConfigurationElement element : elements) {
+ if(element.getName().equals(ELEMENT_LIFECYCLE_MAPPING)) {
+ if(mappingId.equals(element.getAttribute(ATTR_ID)))
+ return createLifecycleMapping(element);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public static AbstractProjectConfigurator getProjectConfigurator(String configuratorId) {
+ return createProjectConfigurator(configuratorId, false/*bare*/);
+ }
+
+ protected static AbstractProjectConfigurator createProjectConfigurator(String configuratorId, boolean bare) {
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint configuratorsExtensionPoint = registry.getExtensionPoint(EXTENSION_PROJECT_CONFIGURATORS);
+ if(configuratorsExtensionPoint != null) {
+ IExtension[] configuratorExtensions = configuratorsExtensionPoint.getExtensions();
+ for(IExtension extension : configuratorExtensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for(IConfigurationElement element : elements) {
+ if(element.getName().equals(ELEMENT_CONFIGURATOR)) {
+ if(configuratorId.equals(element.getAttribute(AbstractProjectConfigurator.ATTR_ID))) {
+ try {
+ AbstractProjectConfigurator configurator = (AbstractProjectConfigurator) element
+ .createExecutableExtension(AbstractProjectConfigurator.ATTR_CLASS);
+
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ configurator.setProjectManager(plugin.getMavenProjectManager());
+ configurator.setMavenConfiguration(plugin.getMavenConfiguration());
+ configurator.setMarkerManager(plugin.getMavenMarkerManager());
+ configurator.setConsole(plugin.getConsole());
+
+ if(!bare) {
+ for(IConfigurationElement mojo : element.getChildren(ELEMENT_MOJO)) {
+ configurator.addPluginExecutionFilter(createPluginExecutionFilter(mojo));
+ }
+ }
+
+ return configurator;
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public static AbstractProjectConfigurator createProjectConfiguratorFor(MojoExecution execution) {
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint configuratorsExtensionPoint = registry.getExtensionPoint(EXTENSION_PROJECT_CONFIGURATORS);
+ if(configuratorsExtensionPoint != null) {
+ IExtension[] configuratorExtensions = configuratorsExtensionPoint.getExtensions();
+ for(IExtension extension : configuratorExtensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for(IConfigurationElement element : elements) {
+ if(element.getName().equals(ELEMENT_CONFIGURATOR)) {
+ if(isConfiguratorEnabledFor(element, execution)) {
+ try {
+ AbstractProjectConfigurator configurator = (AbstractProjectConfigurator) element
+ .createExecutableExtension(AbstractProjectConfigurator.ATTR_CLASS);
+
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ configurator.setProjectManager(plugin.getMavenProjectManager());
+ configurator.setMavenConfiguration(plugin.getMavenConfiguration());
+ configurator.setMarkerManager(plugin.getMavenMarkerManager());
+ configurator.setConsole(plugin.getConsole());
+
+ for(IConfigurationElement mojo : element.getChildren(ELEMENT_MOJO)) {
+ configurator.addPluginExecutionFilter(createPluginExecutionFilter(mojo));
+ }
+
+ return configurator;
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static boolean isConfiguratorEnabledFor(IConfigurationElement configuration, MojoExecution execution) {
+ for(IConfigurationElement mojo : configuration.getChildren(ELEMENT_MOJO)) {
+ if(createPluginExecutionFilter(mojo).match(execution)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/messages.properties b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/messages.properties
new file mode 100644
index 00000000..4c740352
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/messages.properties
@@ -0,0 +1,498 @@
+AbstractProjectConfigurator_error_missing_nature=Project does not have required nature
+AbstractTransferListenerAdapter_4=0% {0}
+AbstractTransferListenerAdapter_byte=B
+AbstractTransferListenerAdapter_cancelled=Transfer is canceled
+AbstractTransferListenerAdapter_kb=KB
+AbstractTransferListenerAdapter_mb=MB
+AbstractTransferListenerAdapter_subtask=error {0}
+AddDependencyAction_error_msg=Can't add dependency to {0}
+AddDependencyAction_error_title=Add Dependency
+AddDependencyAction_searchDialog_title=Add Dependency
+AddDependencyDialog_artifactId_label=Artifact Id:
+AddDependencyDialog_groupId_label=Group Id:
+AddDependencyDialog_info_label=Info:
+AddDependencyDialog_info_transitive={0}-{1}-{2} is already a transitive dependency.\n
+AddDependencyDialog_itemsSelected={0} items selected.
+AddDependencyDialog_itemSelected={0} item selected.
+AddDependencyDialog_multipleValuesSelected=(multiple values selected)
+AddDependencyDialog_results_label=Search Results:
+AddDependencyDialog_scope_label=Scope:
+AddDependencyDialog_search_label=Enter coordinate, sha1 prefix, project name..
+AddDependencyDialog_search_message=(coordinate, sha1 prefix, project name)
+AddDependencyDialog_searchDone=Done. {0} results found.
+AddDependencyDialog_searchError=Error while searching: {0}
+AddDependencyDialog_searching=Searching...
+AddDependencyDialog_searchingFor=Searching for {0}...
+AddDependencyDialog_title=Add Dependency
+AddDependencyDialog_tooManyResults=Too many results. Please refine your search.
+AddDependencyDialog_transitive_dependency=\ \ + {0}-{1}-{2} is already a transitive dependency.\n
+AddDependencyDialog_version_label=Version:
+AddPluginAction_searchDialog_title=Add Plugin
+ArchetypeCatalogFactory_default_local=Default Local
+ArchetypeCatalogFactory_error_missing_catalog=Error looking up archetype catalog; {0}
+ArchetypeCatalogFactory_indexer_catalog=Nexus Indexer
+ArchetypeCatalogFactory_internal=Internal
+ArchetypeCatalogFactory_local=Local {0}
+ArchetypeCatalogFactory_remote=Remote {0}
+ArchetypeCatalogsWriter_error_parse=Unable to parse Archetype catalogs list; {0}
+ArchetypeCatalogsWriter_error_write=Unable to write Archetype catalogs; {0}
+AsyncFetcher_error_cancelled=transfer has been cancelled by user
+AsyncFetcher_error_server=Server returned status code {0}: {1}
+AsyncFetcher_task_fetching=Fetching {0}
+AsyncFetcher_task_fetching2=Fetching {0} ({1}%)
+ChangeNatureAction_job_changing=Changing nature
+ChangeNatureAction_status_error=Can't change nature
+CustomArchetypeDialog_error_artid=Archetype Artifact Id is required
+CustomArchetypeDialog_error_grid=Archetype Group Id is required
+CustomArchetypeDialog_error_version=Archetype Version is required
+CustomArchetypeDialog_lblArchetypeartifactid=Archetype Artifact Id:
+CustomArchetypeDialog_lblArchetypegroupId=Archetype Group Id:
+CustomArchetypeDialog_lblArchetypeversion=Archetype Version:
+CustomArchetypeDialog_lblRepo=Repository URL:
+CustomArchetypeDialog_message=Specify Archetype and Maven repository URL
+CustomizableLifecycleMappingPropertyPage_message=Customizable Lifecycle Mapping
+CustomRepositoriesNode_name=Custom Repositories
+DefaultMavenMenuCreator_action_ci=Open Continuous Integration
+DefaultMavenMenuCreator_action_dependency=Add Dependency
+DefaultMavenMenuCreator_action_disable_management=Disable Dependency Management
+DefaultMavenMenuCreator_action_disable_workspace=Disable Workspace Resolution
+DefaultMavenMenuCreator_action_enable_dm=Enable Dependency Management
+DefaultMavenMenuCreator_action_enable_workspace=Enable Workspace Resolution
+DefaultMavenMenuCreator_action_issues=Open Issue Tracker
+DefaultMavenMenuCreator_action_open_pom=Open POM
+DefaultMavenMenuCreator_action_plugin=Add Plugin
+DefaultMavenMenuCreator_action_project=Open Project Page
+DefaultMavenMenuCreator_action_project_page=Open Project Page
+DefaultMavenMenuCreator_action_scm=Open Source Control
+DefaultMavenMenuCreator_action_update_config=Update Project Configuration
+DefaultMavenMenuCreator_action_update_deps=Update Dependencies
+DefaultMavenMenuCreator_action_update_snapshots=Update Snapshots
+EclipseLogger_debug1=[DEBUG] {0}
+EclipseLogger_debug2=[DEBUG] {0} {1}
+EclipseLogger_error1=[ERROR] {0}
+EclipseLogger_error2=[ERROR] {0} {1}
+EclipseLogger_fatal1=[FATAL ERROR] {0}
+EclipseLogger_fatal2=[FATAL ERROR] {0} {1}
+EclipseLogger_info1=[INFO] {0}
+EclipseLogger_info2=[INFO] {0} {1}
+EclipseLogger_name=m2e console logger
+EclipseLogger_warn1=[WARN] {0}
+EclipseLogger_warn2=[WARN] {0} {1}
+EditDependencyDialog_artifactId_label=Artifact Id:
+EditDependencyDialog_classifier_label=Classifier:
+EditDependencyDialog_groupId_label=Group Id:
+EditDependencyDialog_optional_checkbox=Optional
+EditDependencyDialog_scope_label=Scope:
+EditDependencyDialog_systemPath_label=System Path:
+EditDependencyDialog_title=Dependency Properties
+EditDependencyDialog_type_label=Type:
+EditDependencyDialog_version_label=Version:
+EmptyLifecycleMappingPropertyPage_title=No lifecycle mapping info to display for the Empty Lifecycle Mapping
+ExtensionReader_foundLifecycleMapping=Found lifecycle mapping id="{0}", name="{1}".
+EnableNatureAction_job_enable=Enabling Maven Dependency Management
+EnableNatureAction_wizard_shell=Create new POM
+GlobalRepositoriesNode_name=Global Repositories
+IndexedArtifactNode_no_pack=[No Packaging]
+IndexUpdaterJob_title=Updating indexes
+LifecycleConfigurationMojoExecutionNotCovered=Mojo execution not covered by lifecycle configuration: {0} (maven lifecycle phase: {1})
+LifecycleMissing=Unknown or missing lifecycle mapping with id="{0}" (project packaging type="{1}")
+LocalArchetypeCatalogDialog_btnBrowse=&Browse...
+LocalArchetypeCatalogDialog_dialog_title=Select Archetype catalog
+LocalArchetypeCatalogDialog_error_empty=Archetype catalog is empty
+LocalArchetypeCatalogDialog_error_exist=Archetype catalog does not exist
+LocalArchetypeCatalogDialog_error_no_location=Archetype catalog location is required
+LocalArchetypeCatalogDialog_lblCatalog=&Catalog File:
+LocalArchetypeCatalogDialog_lblDesc=Description:
+LocalArchetypeCatalogDialog_message=Specify catalog location and description
+LocalArchetypeCatalogDialog_title=Local Archetype Catalog
+LocalProjectScanner_task_scanning=Scanning folders
+LocalRepositoryNode_local=Local Repository
+LocalRepositoryRootNode_name=Local Repositories
+M2EErrorDialog_column_error=Error
+M2EErrorDialog_column_name=Project Name
+MavenArchetypesPreferencePage_btnAddLocal=Add &Local Catalog...
+MavenArchetypesPreferencePage_btnAddRemote=Add &Remote Catalog...
+MavenArchetypesPreferencePage_btnEdit=&Edit...
+MavenArchetypesPreferencePage_btnRemove=&Remove
+MavenArchetypesPreferencePage_error=Can't save archetype catalog configuration\n{0}
+MavenArchetypesPreferencePage_link=Add, remove or edit <a href="\#">Maven Archetype catalogs</a>:
+MavenArchetypesPreferencePage_local=Local: {0}
+MavenArchetypesPreferencePage_packaged=Packaged: {0}
+MavenArchetypesPreferencePage_remote=Remote: {0}
+MavenArchetypesPreferencePage_title=Maven Archetype Catalogs
+MavenCheckoutLocationPage_btnBrowse=&Browse...
+MavenCheckoutLocationPage_btnCheckout=Check out &All projects
+MavenCheckoutLocationPage_btnHead=Check out &Head Revision
+MavenCheckoutLocationPage_btnRevSelect=&Select...
+MavenCheckoutLocationPage_description=Select target location and revision
+MavenCheckoutLocationPage_error_empty=Select SCM type and URL
+MavenCheckoutLocationPage_error_empty_url=SCM URL field is required
+MavenCheckoutLocationPage_error_scm_empty=SCM revision fied is required
+MavenCheckoutLocationPage_error_scm_invalid=SCM revision is invalid
+MavenCheckoutLocationPage_error_url_empty=SCM URL is invalid
+MavenCheckoutLocationPage_lblRevision=&Revision:
+MavenCheckoutLocationPage_lblurl=SCM &URL:
+MavenCheckoutLocationPage_title=Target Location
+MavenCheckoutOperation_task_checking=Checking out {0} {1}
+MavenCheckoutOperation_task_scanning=Scanning {0} {1}
+MavenCheckoutWizard_location1=Select Project Location
+MavenCheckoutWizard_location2=Select project location and working set
+MavenCheckoutWizard_title=Checkout as Maven project from SCM
+MavenConsoleImpl_title=Maven Console
+MavenConsolePageParticipant_any=Show Console on Any Output
+MavenConsolePageParticipant_error=Show Console on Error
+MavenConsoleRemoveAction_tooltip=Close Maven2 Console
+MavenDebugOutputAction_0=Debug Output
+MavenDependenciesWizardPage_lblArtifacts=Maven Artifacts:
+MavenDependenciesWizardPage_searchDialog_title=Add Dependency
+MavenExternalRuntime_error_cannot_parse=Can't parse m2.conf
+MavenExternalRuntime_exc_unsupported=Unsupported m2.conf element
+MavenExternalRuntime_unknown=UNKNOWN
+MavenEmbeddedRuntime_unknown=UNKNOWN
+MavenGoalSelectionDialog_btnQualified=Use &Qualified Name
+MavenGoalSelectionDialog_error=Should select at least one goal
+MavenGoalSelectionDialog_lblSelect=&Select Goal:
+MavenGoalSelectionDialog_message=Select goal:
+MavenImpl_error_calc_build_plan=Could not calculate build plan
+MavenImpl_error_create_repo=Could not create artifact repository
+MavenImpl_error_init_maven=Could not initialize embedded maven runtime
+MavenImpl_error_lookup=Could not lookup required component
+MavenImpl_error_missing=Missing {0}
+MavenImpl_error_mojo=Could not get configured mojo for {0}
+MavenImpl_error_no_exec_req=Could not create maven execution request
+MavenImpl_error_param=Could not get mojo execution paramater value
+MavenImpl_error_read_config=Could not read Maven configuration
+MavenImpl_error_read_lastUpdated=Could not read artifact lastUpdated status
+MavenImpl_error_read_pom=Could not read pom.xml
+MavenImpl_error_read_project=Could not read maven project
+MavenImpl_error_read_settings=Could not read settings.xml
+MavenImpl_error_read_settings2=Can not read settings file {0}
+MavenImpl_error_resolve=Could not resolve artifact
+MavenImpl_error_sort=unable to sort projects
+MavenImpl_error_write_lastUpdated=Could not write artifact lastUpdated status
+MavenImpl_error_write_pom=Could not write pom.xml
+MavenImpl_error_write_settings=Could not write settings.xml
+MavenImportWizard_job=Importing Maven projects
+MavenImportWizard_title=Import Maven projects
+MavenImportWizardPage_desc=Select Maven projects
+MavenImportWizardPage_inherited=[inherited]
+MavenImportWizardPage_title=Maven Projects
+MavenInstallationsPreferencePage_btnAdd=&Add...
+MavenInstallationsPreferencePage_btnEdit=&Edit...
+MavenInstallationsPreferencePage_btnGlobalBrowse=&Browse...
+MavenInstallationsPreferencePage_btnRemove=&Remove
+MavenInstallationsPreferencePage_dialog_install_message=Select Maven installation directory
+MavenInstallationsPreferencePage_dialog_install_title=Maven Installation
+MavenInstallationsPreferencePage_dialog_message=Select Maven installation directory
+MavenInstallationsPreferencePage_dialog_title=Maven Installation
+MavenInstallationsPreferencePage_error_global_missing=Global settings file doesn't exist
+MavenInstallationsPreferencePage_error_global_parse=Unable to parse global settings file;
+MavenInstallationsPreferencePage_error_message=Select the directory where Maven is installed.
+MavenInstallationsPreferencePage_error_title=Maven Install
+MavenInstallationsPreferencePage_error2_message=The selected directory is not a valid Maven directory.
+MavenInstallationsPreferencePage_error3_message=The selected Maven install is already registered.
+MavenInstallationsPreferencePage_error4_message=Selected Maven install is already registered
+MavenInstallationsPreferencePage_job_updating=Updating Maven installation settings
+MavenInstallationsPreferencePage_lblNote1=Note: Embedded runtime is always used for dependency resolution, but
+MavenInstallationsPreferencePage_lblNote2=does not use global settings when it is used to launch Maven. To learn more, visit the <a href="http://maven.apache.org/">maven</a> web page.
+MavenInstallationsPreferencePage_link=Select the installation used to launch maven:
+MavenInstallationsPreferencePage_link_global=Open editor for global settings
+MavenInstallationsPreferencePage_link_open=\ (<a href="\#">open file</a>):
+MavenInstallationsPreferencePage_settings=Global settings
+MavenInstallationsPreferencePage_settings_install=Global settings from installation directory
+MavenInstallationsPreferencePage_title=Maven Installations
+MavenInstallFileArtifactWizardPage_btnChecksum=Create C&hecksum
+MavenInstallFileArtifactWizardPage_btnFilename=&Browse...
+MavenInstallFileArtifactWizardPage_btnGenerate=Gen&erate POM
+MavenInstallFileArtifactWizardPage_btnPom=B&rowse...
+MavenInstallFileArtifactWizardPage_desc=Install file in local repository
+MavenInstallFileArtifactWizardPage_error_artifactid=Artifact Id must be specified
+MavenInstallFileArtifactWizardPage_error_groupid=Group Id must be specified
+MavenInstallFileArtifactWizardPage_error_missing=Artifact file does not exist
+MavenInstallFileArtifactWizardPage_error_missingpom=POM file does not exist
+MavenInstallFileArtifactWizardPage_error_no_name=Artifact file name must be specified
+MavenInstallFileArtifactWizardPage_error_packaging=Packaging must be specified
+MavenInstallFileArtifactWizardPage_error_version=Version must be specified
+MavenInstallFileArtifactWizardPage_file_title=Select file
+MavenInstallFileArtifactWizardPage_lblArtifact=&Artifact Id:
+MavenInstallFileArtifactWizardPage_lblClassifier=&Classifier:
+MavenInstallFileArtifactWizardPage_lblFileName=Artifact &file:
+MavenInstallFileArtifactWizardPage_lblgroupid=&Group Id:
+MavenInstallFileArtifactWizardPage_lblPackaging=&Packaging:
+MavenInstallFileArtifactWizardPage_lblPom=&POM file:
+MavenInstallFileArtifactWizardPage_lblVersion=&Version:
+MavenInstallFileArtifactWizardPage_message=Selected artifact corresponds to {0}
+MavenInstallFileArtifactWizardPage_title=Install file in local repository
+MavenInstallFileWizard_error=Execution error
+MavenInstallFileWizard_job=Installing artifact
+MavenInstallFileWizard_title=Install artifact
+MavenMarkerManager_duplicate_groupid=GroupId is duplicate of parent groupId
+MavenMarkerManager_duplicate_version=Version is duplicate of parent version
+MavenMarkerManager_error_artifact=Artifact error
+MavenMarkerManager_error_missing=Missing artifact {0}
+MavenMarkerManager_error_noschema=There is no schema defined for this pom.xml.
+MavenMarkerManager_error_offline=Offline / {0}
+MavenMarkerManager_managed_title=Overriding managed version {0} for {1}
+MavenMarkerManager_metadata_resolution=Metadata resolution error
+MavenMaterializePomWizard_btnCheckout=&Check out All projects
+MavenMaterializePomWizard_btnDev=Use &Developer connection
+MavenMaterializePomWizard_dialog_message=Select Maven artifacts to import
+MavenMaterializePomWizard_dialog_title=Select Maven artifacts
+MavenMaterializePomWizard_location_message=Select project location and working set
+MavenMaterializePomWizard_location_title=Select project location
+MavenMaterializePomWizard_title=Import Maven Projects
+MavenModelManager_error_cannot_load=Can't load model {0}
+MavenModelManager_error_create=Can't create model {0}; {1}
+MavenModelManager_error_pom_exists=POM {0} already exists
+MavenModelManager_error_read=Project read error
+MavenModelManager_monitor_building=Building dependency tree
+MavenModelManager_monitor_reading=Reading project
+MavenModuleWizardParentPage_error=The parent project must have a packaging type of POM
+MavenPlugin_error_jre_message=The Maven Integration requires that Eclipse be running in a JDK, because a number of Maven core plugins are using jars from the JDK.\n\nPlease make sure the -vm option in <a>eclipse.ini</a> is pointing to a JDK and verify that <a>Installed JREs</a> are also using JDK installs.
+MavenPlugin_error_jre_title=Maven Integration for Eclipse JDK Warning
+MavenPlugin_error_warn_again=Do not warn again
+MavenPomSelectionComponent_btnJavadoc=Include Javadocs
+MavenPomSelectionComponent_btnSource=Include Sources
+MavenPomSelectionComponent_btnTests=Include Tests
+MavenPomSelectionComponent_detail1={0} ({1})
+MavenPomSelectionComponent_details2={0}, size: {1} b
+MavenPomSelectionComponent_error=Search error: {0}
+MavenPomSelectionComponent_lblResults=&Search Results:
+MavenPomSelectionComponent_managed_decoration=\ \ (managed)
+MavenPomSelectionComponent_nosel=No selection
+MavenPomSelectionComponent_results=Results for ''{0}'' ({1})
+MavenPomSelectionComponent_search_title=&Enter groupId, artifactId or sha1 prefix or pattern (*):
+MavenPomSelectionComponent_searching=Searching ''{0}''...
+MavenPomSelectionComponent_searchJob=Repository search
+MavenPomSelectionComponent_selected=Selected {0}
+MavenPomSelectionComponent_toomany=Too many results to display. Enter a more specific search term.
+MavenPomSelectionComponent_tooshort=Query ''{0}'' is too short
+MavenPomWizard_error_exists=POM already exists
+MavenPomWizard_error_title=Error
+MavenPomWizard_status_not_exists=Folder "{0}" does not exist.
+MavenPomWizard_task=Creating POM
+MavenPomWizard_title=Maven POM wizard
+MavenPomWizardPage_btnBrowse=Browse...
+MavenPomWizardPage_desc=This wizard creates a new POM (pom.xml) descriptor for Maven2.
+MavenPomWizardPage_dialog_title=Select project
+MavenPomWizardPage_error_artid=Artifact Id must be specified
+MavenPomWizardPage_error_folder=Project or folder must be specified
+MavenPomWizardPage_error_folder_write=Folder must be writable
+MavenPomWizardPage_error_folder2=Folder must exist
+MavenPomWizardPage_error_grid=Group Id must be specified
+MavenPomWizardPage_error_pack=Packaging must be specified
+MavenPomWizardPage_error_version=Version must be specified
+MavenPomWizardPage_lblProject=&Project:
+MavenPomWizardPage_title=Maven2 POM
+MavenPreferencePage_download=Download repository index updates on startup
+MavenPreferencePage_hide=Hide folders of physically nested modules (experimental)
+MavenPreferencePage_select=&Select...
+MavenPreferencePage_select2=S&elect...
+MavenPreferencePage_update=Update Maven projects on startup
+MavenProjectCheckoutJob_confirm_message=No Maven projects found, but there is Eclipse projects configuration avaialble.\nDo you want to select and import Eclipse projects?
+MavenProjectCheckoutJob_confirm_title=Project Import
+MavenProjectCheckoutJob_confirm2_message=No Maven projects found. Do you want to create project using new project wizard?\nCheck out location will be copied into clipboard.
+MavenProjectCheckoutJob_confirm2_title=Project Import
+MavenProjectCheckoutJob_job=Importing Maven projects
+MavenProjectCheckoutJob_title=Checking out Maven projects
+MavenProjectFacade_error=Could not read maven project
+MavenProjectLifecycleMappingPage_error_no_page=No lifecycle mapping property page found.
+MavenProjectLifecycleMappingPage_error_no_strategy=No lifecycle mapping strategy found.
+MavenProjectLifecycleMappingPage_error_page_error=Unable to load the lifecycle mapping property page.
+MavenProjectPomScanner_23=Reading model {0}:{1}:{2}
+MavenProjectPomScanner_task_resolving=Resolving artifact {0}:{1}:{2}
+MavenProjectPreferencePage_btnResolve=Resolve dependencies from &Workspace projects
+MavenProjectPreferencePage_dialog_message=Maven settings has changed. Do you want to update project configuration?
+MavenProjectPreferencePage_dialog_title=Maven Settings
+MavenProjectPreferencePage_job=Updating {0} Sources
+MavenProjectPreferencePage_lblProfiles=Active Maven &Profiles (comma separated):
+MavenProjectPreferencePage_title=Maven
+MavenProjectWizardArchetypePage_add_title=Add Archetype
+MavenProjectWizardArchetypePage_all=All Catalogs
+MavenProjectWizardArchetypePage_btnAdd=&Add Archetype...
+MavenProjectWizardArchetypePage_btnConfigure=Con&figure...
+MavenProjectWizardArchetypePage_btnLast=&Show the last version of Archetype only
+MavenProjectWizardArchetypePage_btnSnapshots=&Include snapshot archetypes
+MavenProjectWizardArchetypePage_error_no=No archetypes currently available. The archetype list will refresh when the indexes finish updating.
+MavenProjectWizardArchetypePage_error_read=Unable to read catalog factory.
+MavenProjectWizardArchetypePage_error_resolve=The archetype {0} could not be resolved.
+MavenProjectWizardArchetypePage_error_resolve2=Can't resolve Archetype {0}
+MavenProjectWizardArchetypePage_lblCatalog=C&atalog:
+MavenProjectWizardArchetypePage_lblFilter=&Filter:
+MavenProjectWizardArchetypePage_task_downloading=Downloading Archetype
+MavenProjectWizardArchetypePage_task_indexing=indexing...
+MavenProjectWizardArchetypePage_task_reading=reading project...
+MavenProjectWizardArchetypePage_task_resolving=resolving POM...
+MavenProjectWizardArchetypePage_task_resolving2=resolving JAR...
+MavenProjectWizardArchetypeParametersPage_btnAdd=&Add...
+MavenProjectWizardArchetypeParametersPage_btnRemove=&Remove
+MavenProjectWizardArchetypeParametersPage_columnName=Name
+MavenProjectWizardArchetypeParametersPage_columnValue=Value
+MavenProjectWizardArchetypeParametersPage_error_download=Error downloading archetype {0}
+MavenProjectWizardArchetypeParametersPage_error_package=Invalid package name
+MavenProjectWizardArchetypeParametersPage_lblProps=Properties available from archetype:
+MavenProjectWizardArchetypeParametersPage_task=Downloading Archetype {0}
+MavenProjectWizardArtifactPage_searchDialog_title=Select Parent Artifact
+MavenProjectWizardLocationPage_btnLocation=Brows&e...
+MavenProjectWizardLocationPage_btnUserDefault=Use default &Workspace location
+MavenProjectWizardLocationPage_dialog_location=Select Location
+MavenProjectWizardLocationPage_lblLocation=&Location:
+MavenRepositorySearchDialog_7=compile
+MavenRepositorySearchDialog_lblScope=Scope:
+MavenRepositoryView_action_copy=Copy URL
+MavenRepositoryView_action_copy_tooltip=Copy URL to Clipboard
+MavenRepositoryView_action_disable_tooltip=Disable repository index
+MavenRepositoryView_action_enable_tooltip=Enable minimal repository index
+MavenRepositoryView_action_enableFull_tooltip=Enable full repository index
+MavenRepositoryView_action_materialize=Materialize Projects
+MavenRepositoryView_action_open=Open POM
+MavenRepositoryView_action_open_tooltip=Open Maven POM
+MavenRepositoryView_action_rebuild=Rebuild Index
+MavenRepositoryView_action_rebuild_tooltip=Force a rebuild of the maven index
+MavenRepositoryView_action_reload=Reload settings.xml
+MavenRepositoryView_action_update=Update Index
+MavenRepositoryView_btnCollapse=Collapse All
+MavenRepositoryView_btnCollapse_tooltip=Collapse All
+MavenRepositoryView_btnUpdate_tooltip=Update repository index
+MavenRepositoryView_details_disabled=Index Details Disabled
+MavenRepositoryView_disable_details=Disable Index Details
+MavenRepositoryView_enable_full=Enable Full Index
+MavenRepositoryView_enable_minimum=Enable Minimum Index
+MavenRepositoryView_enabled_full=Full Index Enabled
+MavenRepositoryView_error_message=Unable to set the index details due to the following error:\n
+MavenRepositoryView_error_title=Error Setting Index Details
+MavenRepositoryView_job_reloading=Reloading settings.xml
+MavenRepositoryView_minimum_enabled=Minimum Index Enabled
+MavenRepositoryView_rebuild_many=Rebuild Indexes
+MavenRepositoryView_rebuild_msg=Are you sure you want to rebuild the index ''{0}''
+MavenRepositoryView_rebuild_msg2=Are you sure you want to rebuild the selected indexes?
+MavenRepositoryView_rebuild_one=Rebuild Index
+MavenRepositoryView_rebuild_title=Rebuild Index
+MavenRepositoryView_rebuild_title2=Rebuild Indexes
+MavenRepositoryView_reload_msg=This will reload the settings.xml and rebuild the indexes for the repositories. Are you sure you want to reload the settings?
+MavenRepositoryView_reload_title=Reload settings.xml
+MavenRepositoryView_update_more=Update Indexes
+MavenRepositoryView_update_one=Update Index
+MavenSearchPage_btnBrowse=Browse...
+MavenSearchPage_btnSelect=Select All
+MavenSearchPage_btnUnselect=Deselect All
+MavenSearchPage_lblArtifactid=Artifact Id:
+MavenSearchPage_lblClass=Class Name:
+MavenSearchPage_lblGroupid=Group Id:
+MavenSearchPage_lblPackaging=Packaging:
+MavenSearchPage_lblRepos=Repositories:
+MavenSearchPage_lblSha=SHA1:
+MavenSearchPage_lblVersion=Version:
+MavenSearchPage_separator=Label
+MavenSettingsPreferencePage_btnBrowse=&Browse...
+MavenSettingsPreferencePage_btnUpdate=Update Settings
+MavenSettingsPreferencePage_error_missing=User settings file doesn't exist
+MavenSettingsPreferencePage_error_parse=Unable to parse user settings file; {0}
+MavenSettingsPreferencePage_job_indexing=Indexing Local Repository...
+MavenSettingsPreferencePage_job_updating=Updating Maven settings
+MavenSettingsPreferencePage_lblLocal=Local Repository (From merged user and global settings):
+MavenSettingsPreferencePage_link_tooltip=Open editor for user settings
+MavenSettingsPreferencePage_link1=User &Settings:
+MavenSettingsPreferencePage_link2=User &Settings (<a href="\#">open file</a>):
+MavenSettingsPreferencePage_task_updating=Updating progress for {0}
+MavenSettingsPreferencePage_title=Maven User Settings
+MissingLifecycleMapping_name=Unknown or missing lifecycle mapping
+MissingLifecycleMappingPropertyPage_error=Unknown or missing lifecycle mapping with id=`{0}'. \nCheck the spelling and/or install required Eclipse plugins.
+MissingLifecycleMappingPropertyPage_title=Missing lifecycle mapping
+NexusIndexManager_78=nexus-indexer
+NexusIndexManager_error_add_repo=Could not add repository index
+NexusIndexManager_error_read_index=Could not read index details file
+NexusIndexManager_error_reindexing=Reindexing error
+NexusIndexManager_error_root_grp=Can't get root groups for {0}
+NexusIndexManager_error_search=Search error
+NexusIndexManager_error_unexpected=Unexpected exception
+NexusIndexManager_error_write_index=Could not write index details file
+NexusIndexManager_inherited=[inherited]
+NexusIndexManager_task_updating=Updating index {0}
+OpenPomAction_33=Can't open editor for {0}\n{1}
+OpenPomAction_error_download=Can't download {0}
+OpenPomAction_error_download_source=Can't download sources for {0}
+OpenPomAction_error_open_editor=Can't open editor for {0}
+OpenPomAction_error_open_pom=Can't open pom file for {0}
+OpenPomAction_job_opening=Opening POM
+OpenPomAction_open_error_message=Unable to read Maven project
+OpenPomAction_open_error_title=Open POM
+OpenPomAction_open_title=Open Maven POM
+OpenPomAction_title_pom=Search Maven POM
+OpenUrlAction_browser_title=Open Browser
+OpenUrlAction_error_no_ci=Project does't specify Continuous Integration URL
+OpenUrlAction_error_no_issues=Project does't specify issue management URL
+OpenUrlAction_error_no_scm=Project does't specify SCM URL
+OpenUrlAction_error_no_url=Project does't specify project URL
+OpenUrlAction_error_open=Can't download {0} POM
+OpenUrlAction_job_browser=Opening Browser
+OpenUrlAction_open_url_message=Unable to read Maven project
+OpenUrlAction_open_url_title=Open URL
+PomFileContentDescriber_error=Internal Error: XML parser configuration error during content description for Maven POM files
+ProjectConfigurationManager_0=Can't get canonical file for {0}
+ProjectConfigurationManager_error_failed=Failed to create project.
+ProjectConfigurationManager_error_rename=Can't rename {0}
+ProjectConfigurationManager_error_resolve=Could not resolve archetype
+ProjectConfigurationManager_error_resolve2=\ from any of the configured repositories.
+ProjectConfigurationManager_error_targetDir=\ Target directory {0} already exists.
+ProjectConfigurationManager_error_unable_archetype=Unable to create project from archetype {0}
+ProjectConfigurationManager_task_configuring=Configuring Maven projects
+ProjectConfigurationManager_task_creating=Creating project {0}
+ProjectConfigurationManager_task_creating_folders=Creating project folders...
+ProjectConfigurationManager_task_creating_pom=Creating the POM file...
+ProjectConfigurationManager_task_creating_project=Configuring project...
+ProjectConfigurationManager_task_creating_project1=Creating project {0}
+ProjectConfigurationManager_task_creating_workspace=Creating workspace project...
+ProjectConfigurationManager_task_disable_nature=Disable Maven nature
+ProjectConfigurationManager_task_enable_nature=Enable Maven nature
+ProjectConfigurationManager_task_executing_archetype=Executing Archetype {0}:{1}
+ProjectConfigurationManager_task_importing=Importing Maven projects
+ProjectConfigurationManager_task_importing2=Importing project {0}
+ProjectConfigurationManager_task_refreshing=Refreshing projects
+ProjectConfigurationManager_task_updating=Updating configuration for {0}
+ProjectConfiguratorsTable_column_id=Id
+ProjectConfiguratorsTable_column_name=Name
+ProjectConfiguratorsTableContentProvider_no_configs=No Project Configurators
+ProjectRegistryManager_task_project=project {0}
+ProjectRegistryManager_task_refreshing=Refreshing projects
+ProjectRegistryRefreshJob_task_refreshing=Refreshing Maven model
+ProjectRegistryRefreshJob_title=Updating Maven Dependencies
+ProjectRepositoriesNode_name=Project Repositories
+ProjectsImportPage_btnDeselect=&Deselect All
+ProjectsImportPage_btnRefresh=R&efresh
+ProjectsImportPage_btnSelect=&Select All
+ProjectsImportPage_desc=Select non-Maven projects to import
+ProjectsImportPage_dialog_title=Question
+ProjectsImportPage_error_creation=Creation Problems
+ProjectsImportPage_lstProjects=&Projects:
+ProjectsImportPage_message=Some projects were hidden because they exist in the workspace directory
+ProjectsImportPage_overwrite=''{0}'' already exists. Would you like to overwrite it?
+ProjectsImportPage_overwrite2=Overwrite ''{0}'' in folder ''{1}''?
+ProjectsImportPage_task_checking=Checking: {0}
+ProjectsImportPage_task_creating=Creating Projects
+ProjectsImportPage_task_processing=Processing results
+ProjectsImportPage_task_search=Searching for projects
+ProjectsImportPage_title=Import Projects
+ProjectsImportWizard_title=Import
+RemoteArchetypeCatalogDialog_btnVerify=&Verify...
+RemoteArchetypeCatalogDialog_error_empty=Remote catalog is empty
+RemoteArchetypeCatalogDialog_error_read=Unable to read remote catalog;\n{0}
+RemoteArchetypeCatalogDialog_error_required=Archetype catalog url is required
+RemoteArchetypeCatalogDialog_job_download=Downloading remote catalog
+RemoteArchetypeCatalogDialog_lblCatalog=&Catalog File:
+RemoteArchetypeCatalogDialog_lblDesc=Description:
+RemoteArchetypeCatalogDialog_message=Specify catalog url and description
+RemoteArchetypeCatalogDialog_message_found=Found {0} archetype(s)
+RemoteArchetypeCatalogDialog_title=Remote Archetype Catalog
+RepositoryNode_updating=\ [updating]
+RepositoryRegistryUpdateJob_title=Repository registry initialization
+ScmUrl_error=Invalid SCM url {0}
+SelectionUtil_error_cannot_read=Can't read Maven project
+UpdateSourcesAction_error_cannot_update=Unable to update Maven configuration
+UpdateSourcesAction_error_message=Unable to update maven configuration for the following projects:
+UpdateSourcesAction_error_title=Error Updating Maven Configuration
+UpdateSourcesAction_job_update_conf=Updating Maven Configuration
+WorkingSetGroup_btnAddSet=&Add project(s) to working set
+WorkingSetGroup_btnMore=Mor&e...
+WorkingSetGroup_lblSet=Wo&rking set:
+WorkspaceRepositoryNode_name=Workspace Projects
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceConstants.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceConstants.java
new file mode 100644
index 00000000..46dfeae0
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceConstants.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.preferences;
+
+
+/**
+ * Maven preferences constants
+ */
+public interface MavenPreferenceConstants {
+
+ static final String PREFIX = "eclipse.m2."; //$NON-NLS-1$
+
+ /** String */
+ // public static final String P_LOCAL_REPOSITORY_DIR = PREFIX+"localRepositoryDirectory";
+
+ /** true or false */
+ // public static final String P_CHECK_LATEST_PLUGIN_VERSION = PREFIX+"checkLatestPluginVersion";
+
+ /** String ??? */
+ // public static final String P_GLOBAL_CHECKSUM_POLICY = PREFIX+"globalChecksumPolicy";
+
+ /** boolean */
+ public static final String P_OFFLINE = PREFIX + "offline"; //$NON-NLS-1$
+
+ /** boolean */
+ // public static final String P_UPDATE_SNAPSHOTS = PREFIX+"updateSnapshots";
+
+ /** boolean */
+ public static final String P_DEBUG_OUTPUT = PREFIX + "debugOutput"; //$NON-NLS-1$
+
+ /** boolean */
+ public static final String P_DOWNLOAD_SOURCES = PREFIX + "downloadSources"; //$NON-NLS-1$
+
+ /** boolean */
+ public static final String P_DOWNLOAD_JAVADOC = PREFIX + "downloadJavadoc"; //$NON-NLS-1$
+
+ /** String */
+ public static final String P_GLOBAL_SETTINGS_FILE = PREFIX + "globalSettingsFile"; //$NON-NLS-1$
+
+ /** String */
+ public static final String P_USER_SETTINGS_FILE = PREFIX + "userSettingsFile"; //$NON-NLS-1$
+
+ /** String */
+ public static final String P_OUTPUT_FOLDER = PREFIX + "outputFolder"; //$NON-NLS-1$
+
+ /** boolean */
+ public static final String P_DISABLE_JDK_WARNING = PREFIX + "disableJdkwarning"; //$NON-NLS-1$
+
+ /** boolean */
+ public static final String P_DISABLE_JDK_CHECK = PREFIX + "disableJdkCheck"; //$NON-NLS-1$
+
+ /** String */
+ public static final String P_RUNTIMES = PREFIX + "runtimes"; //$NON-NLS-1$
+
+ /** String */
+ public static final String P_DEFAULT_RUNTIME = PREFIX + "defaultRuntime"; //$NON-NLS-1$
+
+ /** boolean */
+ public static final String P_UPDATE_INDEXES = PREFIX + "updateIndexes"; //$NON-NLS-1$
+
+ /** boolean */
+ public static final String P_UPDATE_PROJECTS = PREFIX + "updateProjects"; //$NON-NLS-1$
+
+ /** String */
+ public static final String P_JIRA_USERNAME = PREFIX + "jiraUsername"; //$NON-NLS-1$
+
+ /** String */
+ public static final String P_JIRA_PASSWORD = PREFIX + "jiraPassword"; //$NON-NLS-1$
+
+ /** boolean */
+ public static final String P_HIDE_FOLDERS_OF_NESTED_PROJECTS = PREFIX + "hideFoldersOfNestedProjects"; //$NON-NLS-1$
+
+ public static final String P_SHOW_CONSOLE_ON_ERR = PREFIX+"showConsoleOnErr"; //$NON-NLS-1$
+
+ public static final String P_SHOW_CONSOLE_ON_OUTPUT = PREFIX+"showConsoleOnOutput"; //$NON-NLS-1$
+
+ /** boolean */
+ public static final String P_FULL_INDEX= PREFIX+"fullIndex"; //$NON-NLS-1$
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceInitializer.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceInitializer.java
new file mode 100644
index 00000000..b9ade3d4
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceInitializer.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.preferences;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+import org.apache.maven.cli.MavenCli;
+
+import org.eclipse.m2e.core.MavenPlugin;
+
+
+/**
+ * Maven preferences initializer.
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenPreferenceInitializer extends AbstractPreferenceInitializer {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
+ */
+ public void initializeDefaultPreferences() {
+ IPreferenceStore store = MavenPlugin.getDefault().getPreferenceStore();
+
+ store.setDefault(MavenPreferenceConstants.P_USER_SETTINGS_FILE, //
+ MavenCli.DEFAULT_USER_SETTINGS_FILE.getAbsolutePath());
+
+ store.setDefault(MavenPreferenceConstants.P_GLOBAL_SETTINGS_FILE, ""); //$NON-NLS-1$
+
+ store.setDefault(MavenPreferenceConstants.P_DEBUG_OUTPUT, false);
+
+ store.setDefault(MavenPreferenceConstants.P_OFFLINE, false);
+
+ store.setDefault(MavenPreferenceConstants.P_DOWNLOAD_SOURCES, false);
+ store.setDefault(MavenPreferenceConstants.P_DOWNLOAD_JAVADOC, false);
+
+ // store.setDefault( MavenPreferenceConstants.P_GLOBAL_CHECKSUM_POLICY, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN);
+ // store.setDefault( MavenPreferenceConstants.P_UPDATE_SNAPSHOTS, false);
+ // store.setDefault( MavenPreferenceConstants.P_CHECK_LATEST_PLUGIN_VERSION, false);
+
+ store.setDefault(MavenPreferenceConstants.P_OUTPUT_FOLDER, "target-eclipse"); //$NON-NLS-1$
+
+ store.setDefault(MavenPreferenceConstants.P_RUNTIMES, ""); //$NON-NLS-1$
+ store.setDefault(MavenPreferenceConstants.P_DEFAULT_RUNTIME, ""); //$NON-NLS-1$
+
+ store.setDefault(MavenPreferenceConstants.P_UPDATE_INDEXES, true);
+ store.setDefault(MavenPreferenceConstants.P_UPDATE_PROJECTS, false);
+
+ store.setDefault(MavenPreferenceConstants.P_HIDE_FOLDERS_OF_NESTED_PROJECTS, false);
+
+ store.setDefault(MavenPreferenceConstants.P_SHOW_CONSOLE_ON_ERR, true);
+ store.setDefault(MavenPreferenceConstants.P_SHOW_CONSOLE_ON_OUTPUT, false);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ArtifactKeyAdapterFactory.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ArtifactKeyAdapterFactory.java
new file mode 100644
index 00000000..aff02f61
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ArtifactKeyAdapterFactory.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+
+
+/**
+ * Adapter factory for ArtifactKey
+ *
+ * @author Igor Fedorenko
+ */
+@SuppressWarnings("unchecked")
+public class ArtifactKeyAdapterFactory implements IAdapterFactory {
+
+ private static final Class[] ADAPTER_LIST = new Class[] {ArtifactKey.class,};
+
+ public Object getAdapter(Object adaptable, Class adapterType) {
+ if(!ArtifactKey.class.equals(adapterType)) {
+ return null;
+ }
+
+ MavenProjectManager projectManager = MavenPlugin.getDefault().getMavenProjectManager();
+ if(adaptable instanceof IProject) {
+ IProject project = (IProject) adaptable;
+ IMavenProjectFacade facade = projectManager.create(project, new NullProgressMonitor());
+ if(facade != null) {
+ return facade.getArtifactKey();
+ }
+ } else if(adaptable instanceof IFile) {
+ IFile file = (IFile) adaptable;
+ if(IMavenConstants.POM_FILE_NAME.equals(file.getName())) {
+ IMavenProjectFacade facade = projectManager.create(file, true, new NullProgressMonitor());
+ if(facade != null) {
+ return facade.getArtifactKey();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Class[] getAdapterList() {
+ // target type
+ return ADAPTER_LIST;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/DependencyResolutionContext.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/DependencyResolutionContext.java
new file mode 100644
index 00000000..71031ae3
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/DependencyResolutionContext.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+
+import org.apache.maven.execution.MavenExecutionRequest;
+
+import org.eclipse.m2e.core.project.MavenUpdateRequest;
+
+/**
+ * @author igor
+ */
+public class DependencyResolutionContext {
+
+ /** Original update request */
+ private final MavenUpdateRequest request;
+
+ /** Set of all pom files to resolve */
+ private final Set<IFile> pomFiles = new LinkedHashSet<IFile>();
+
+ /** Set of pom files to resolve regardless of their isStale() state */
+ private final Set<IFile> forcedPomFiles = new HashSet<IFile>();
+
+ /** The template request for invocations of Maven */
+ private MavenExecutionRequest executionRequest;
+
+ public DependencyResolutionContext(MavenUpdateRequest request, MavenExecutionRequest executionRequest) {
+ this.request = request;
+ this.pomFiles.addAll(request.getPomFiles());
+ this.executionRequest = executionRequest;
+ }
+
+ public boolean isEmpty() {
+ return pomFiles.isEmpty();
+ }
+
+ public void forcePomFiles(Set<IFile> pomFiles) {
+ this.pomFiles.addAll(pomFiles);
+ this.forcedPomFiles.addAll(pomFiles);
+ }
+
+ public MavenUpdateRequest getRequest() {
+ return request;
+ }
+
+ public MavenExecutionRequest getExecutionRequest() {
+ return executionRequest;
+ }
+
+ public boolean isForce(IFile pom) {
+ return request.isForce() || forcedPomFiles.contains(pom);
+ }
+
+ public IFile pop() {
+ Iterator<IFile> i = pomFiles.iterator();
+ IFile pom = i.next();
+ i.remove();
+ return pom;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/EclipseMavenMetadataCache.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/EclipseMavenMetadataCache.java
new file mode 100644
index 00000000..292a9137
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/EclipseMavenMetadataCache.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.eclipse.core.resources.IFile;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.ResolutionGroup;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.project.artifact.DefaultMavenMetadataCache;
+import org.apache.maven.project.artifact.MavenMetadataCache;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+
+/**
+ * EclipseMavenMetadataCache
+ *
+ * @author igor
+ */
+public class EclipseMavenMetadataCache extends DefaultMavenMetadataCache implements MavenMetadataCache, IManagedCache {
+
+ public void put(Artifact artifact, boolean resolveManagedVersions, ArtifactRepository localRepository,
+ List<ArtifactRepository> remoteRepositories, ResolutionGroup result) {
+
+ ArtifactKey gav = new ArtifactKey(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), null);
+
+ if ("pom".equals(artifact.getType()) ) { //$NON-NLS-1$
+ // new project pom, remove any existing project entries
+ removeProject(gav);
+ }
+
+ super.put(artifact, resolveManagedVersions, localRepository, remoteRepositories, result);
+ }
+
+ public void removeProject(IFile pom, ArtifactKey key) {
+ removeProject(key);
+ }
+
+ private void removeProject(ArtifactKey key) {
+ if(key == null) {
+ return;
+ }
+
+ Iterator<Entry<CacheKey, CacheRecord>> iter = cache.entrySet().iterator();
+
+ while(iter.hasNext()) {
+ Entry<CacheKey, CacheRecord> entry = iter.next();
+ CacheRecord record = entry.getValue();
+
+ if(equals(record.getArtifact(), key) || contains(record.getArtifacts(), key)) {
+ iter.remove();
+ }
+ }
+ }
+
+ private boolean contains(List<Artifact> artifacts, ArtifactKey key) {
+ for(Artifact artifact : artifacts) {
+ if(equals(artifact, key)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean equals(Artifact artifact, ArtifactKey key) {
+ /*
+ * maybe too conservative, but purge anything that matches GAbV (bV==baseVersion)
+ */
+ return eq(key.getGroupId(), artifact.getGroupId()) //
+ && eq(key.getArtifactId(), artifact.getArtifactId()) //
+ && eq(key.getVersion(), artifact.getBaseVersion());
+ }
+
+ private static <T> boolean eq(T a, T b) {
+ return a != null ? a.equals(b) : b == null;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/IManagedCache.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/IManagedCache.java
new file mode 100644
index 00000000..6eb2d41c
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/IManagedCache.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import org.eclipse.core.resources.IFile;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+/**
+ * IManagedCache
+ *
+ * @author igor
+ */
+public interface IManagedCache {
+
+ /**
+ * @param pom
+ * @param mavenProject
+ */
+ void removeProject(IFile pom, ArtifactKey mavenProject);
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/IgnoreMojoProjectConfiguration.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/IgnoreMojoProjectConfiguration.java
new file mode 100644
index 00000000..b8090934
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/IgnoreMojoProjectConfiguration.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator;
+import org.eclipse.m2e.core.project.configurator.ProjectConfigurationRequest;
+
+
+/**
+ * IgnoreMojoProjectConfiguration
+ *
+ * @author igor
+ */
+public class IgnoreMojoProjectConfiguration extends AbstractProjectConfigurator {
+
+ public IgnoreMojoProjectConfiguration() {
+ }
+
+ public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) {
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MavenMarkerManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MavenMarkerManager.java
new file mode 100644
index 00000000..cc1c98a7
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MavenMarkerManager.java
@@ -0,0 +1,713 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.w3c.dom.Comment;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
+import org.eclipse.wst.xml.core.internal.parser.regions.TagNameRegion;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
+import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.DependencyManagement;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginManagement;
+import org.apache.maven.model.building.ModelBuildingException;
+import org.apache.maven.model.building.ModelProblem;
+import org.apache.maven.model.building.ModelProblem.Severity;
+import org.apache.maven.project.DependencyResolutionResult;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuildingException;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.project.IMavenMarkerManager;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+
+@SuppressWarnings("restriction")
+public class MavenMarkerManager implements IMavenMarkerManager {
+ private static final String XSI_SCHEMA_LOCATION = "xsi:schemaLocation"; //$NON-NLS-1$
+
+ private static final String PROJECT_NODE = "project"; //$NON-NLS-1$
+ public static final String OFFSET = "offset"; //$NON-NLS-1$
+
+ private final MavenConsole console;
+ private final IMavenConfiguration mavenConfiguration;
+
+ public MavenMarkerManager(MavenConsole console, IMavenConfiguration mavenConfiguration) {
+ this.console = console;
+ this.mavenConfiguration = mavenConfiguration;
+ }
+
+ public void addMarkers(IResource pomFile, String type, MavenExecutionResult result) {
+ List<Throwable> exceptions = result.getExceptions();
+
+ for(Throwable ex : exceptions) {
+ if(ex instanceof ProjectBuildingException) {
+ handleProjectBuildingException(pomFile, type, (ProjectBuildingException) ex);
+ } else if(ex instanceof AbstractArtifactResolutionException) {
+ AbstractArtifactResolutionException rex = (AbstractArtifactResolutionException) ex;
+ String errorMessage = getArtifactId(rex) + " " + getErrorMessage(ex); //$NON-NLS-1$
+ addMarker(pomFile, type, errorMessage, 1, IMarker.SEVERITY_ERROR);
+ } else {
+ handleBuildException(pomFile, type, ex);
+ }
+ }
+
+ DependencyResolutionResult resolutionResult = result.getDependencyResolutionResult();
+ if(resolutionResult != null) {
+ // @see also addMissingArtifactMarkers
+ addErrorMarkers(pomFile, type, org.eclipse.m2e.core.internal.Messages.MavenMarkerManager_metadata_resolution,
+ resolutionResult.getCollectionErrors());
+ for(org.sonatype.aether.graph.Dependency dependency : resolutionResult.getUnresolvedDependencies()) {
+ addErrorMarkers(pomFile, type, org.eclipse.m2e.core.internal.Messages.MavenMarkerManager_error_artifact,
+ resolutionResult.getResolutionErrors(dependency));
+ }
+ }
+
+ MavenProject mavenProject = result.getProject();
+ if (mavenProject != null) {
+ addMissingArtifactMarkers(pomFile, type, mavenProject);
+ }
+ }
+
+ public void addEditorHintMarkers(IResource pomFile, String type) {
+ checkForSchema(pomFile, type);
+ //mkleint: adding here but I'm sort of not entirely clear what the usage patter of this class is.
+ checkVarious(pomFile, type);
+ }
+
+ /**
+ * @param pomFile
+ */
+ private void checkVarious(IResource pomFile, String type) {
+ IDOMModel domModel = null;
+ try {
+ if(!(pomFile instanceof IFile)) {
+ return;
+ }
+ domModel = (IDOMModel) StructuredModelManager.getModelManager().getModelForRead((IFile) pomFile);
+ IStructuredDocument document = domModel.getStructuredDocument();
+ Element root = domModel.getDocument().getDocumentElement();
+
+ if(root.getNodeName().equals("project")) { //$NON-NLS-1$
+ //now check parent version and groupid against the current project's ones..
+ checkParentMatchingGroupIdVersion(root, pomFile, type, document);
+ checkManagedDependencies(root, pomFile, type, document);
+ checkManagedPlugins(root, pomFile, type, document);
+ }
+ } catch(Exception t) {
+ MavenLogger.log("Error checking for warnings", t); //$NON-NLS-1$
+ } finally {
+ if(domModel != null) {
+ domModel.releaseFromRead();
+ }
+ }
+ }
+
+ private void checkManagedDependencies(Element root, IResource pomFile, String type, IStructuredDocument document)
+ throws CoreException {
+ IProject prj = pomFile.getProject();
+ //the project returned is in a way unrelated to nested child poms that don't have an opened project,
+ //in that case we pass along a wrong parent/aggregator
+ if (prj == null || pomFile.getProjectRelativePath().segmentCount() != 1) {
+ //if the project were the pom's project, the relative path would be just "pom.xml", if it's not just throw it out of the window..
+ return;
+ }
+ IMavenProjectFacade facade = MavenPlugin.getDefault().getMavenProjectManager().getProject(prj);
+ if (facade == null) {
+ return;
+ }
+ MavenProject mavenproject = facade.getMavenProject();
+ if (mavenproject == null) {
+ //we only work with cached instances here, never loading ourselves..
+ return;
+ }
+ List<Element> candidates = new ArrayList<Element>();
+
+ Element dependencies = findChildElement(root, "dependencies"); //$NON-NLS-1$
+ if (dependencies != null) {
+ for (Element el : findChildElements(dependencies, "dependency")) { //$NON-NLS-1$
+ Element version = findChildElement(el, "version"); //$NON-NLS-1$
+ if (version != null) {
+ candidates.add(el);
+ }
+ }
+ }
+ //we should also consider <dependencies> section in the profiles, but profile are optional and so is their
+ // dependencyManagement section.. that makes handling our markers more complex.
+ // see MavenProject.getInjectedProfileIds() for a list of currently active profiles in effective pom
+ String currentProjectKey = mavenproject.getGroupId() + ":" + mavenproject.getArtifactId() + ":" + mavenproject.getVersion(); //$NON-NLS-1$ //$NON-NLS-2$
+ List<String> activeprofiles = mavenproject.getInjectedProfileIds().get(currentProjectKey);
+ //remember what profile we found the dependency in.
+ Map<Element, String> candidateProfile = new HashMap<Element, String>();
+ Element profiles = findChildElement(root, "profiles"); //$NON-NLS-1$
+ if (profiles != null) {
+ for (Element profile : findChildElements(profiles, "profile")) { //$NON-NLS-1$
+ String idString = getElementTextValue(findChildElement(profile, "id")); //$NON-NLS-1$
+ if (idString != null && activeprofiles.contains(idString)) {
+ dependencies = findChildElement(profile, "dependencies"); //$NON-NLS-1$
+ if (dependencies != null) {
+ for (Element el : findChildElements(dependencies, "dependency")) { //$NON-NLS-1$
+ Element version = findChildElement(el, "version"); //$NON-NLS-1$
+ if (version != null) {
+ candidates.add(el);
+ candidateProfile.put(el, idString);
+ }
+ }
+ }
+ }
+ }
+ }
+ //collect the managed dep ids
+ Map<String, String> managed = new HashMap<String, String>();
+ DependencyManagement dm = mavenproject.getDependencyManagement();
+ if (dm != null) {
+ List<Dependency> deps = dm.getDependencies();
+ if (deps != null) {
+ for (Dependency dep : deps) {
+ //shall we be using geManagementkey() here? but it contains also the type, not only the gr+art ids..
+ managed.put(dep.getGroupId() + ":" + dep.getArtifactId(), dep.getVersion()); //$NON-NLS-1$
+ }
+ }
+ }
+
+ //now we have all the candidates, match them against the effective managed set
+ for(Element dep : candidates) {
+ Element version = findChildElement(dep, "version"); //$NON-NLS-1$
+ String grpString = getElementTextValue(findChildElement(dep, "groupId")); //$NON-NLS-1$
+ String artString = getElementTextValue(findChildElement(dep, "artifactId")); //$NON-NLS-1$
+ String versionString = getElementTextValue(version);
+ if(grpString != null && artString != null && versionString != null) {
+ String id = grpString + ":" + artString; //$NON-NLS-1$
+ if(managed.containsKey(id)) {
+ String managedVersion = managed.get(id);
+ if(version instanceof IndexedRegion) {
+ IndexedRegion off = (IndexedRegion) version;
+ if(lookForIgnoreMarker(document, version, off, IMavenConstants.MARKER_IGNORE_MANAGED)) {
+ continue;
+ }
+
+ IMarker mark = addMarker(pomFile, type, NLS.bind(
+ org.eclipse.m2e.core.internal.Messages.MavenMarkerManager_managed_title, managedVersion, artString),
+ document.getLineOfOffset(off.getStartOffset()) + 1, IMarker.SEVERITY_WARNING, false /*isTransient*/);
+ mark.setAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT,
+ IMavenConstants.EDITOR_HINT_MANAGED_DEPENDENCY_OVERRIDE);
+ mark.setAttribute(IMarker.CHAR_START, off.getStartOffset());
+ mark.setAttribute(IMarker.CHAR_END, off.getEndOffset());
+ mark.setAttribute("problemType", "pomhint"); //only imporant in case we enable the generic xml quick fixes //$NON-NLS-1$ //$NON-NLS-2$
+ //add these attributes to easily and deterministicaly find the declaration in question
+ mark.setAttribute("groupId", grpString); //$NON-NLS-1$
+ mark.setAttribute("artifactId", artString); //$NON-NLS-1$
+ String profile = candidateProfile.get(dep);
+ if(profile != null) {
+ mark.setAttribute("profile", profile); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static boolean lookForIgnoreMarker(IStructuredDocument document, Element version, IndexedRegion off, String ignoreString) {
+ Node reg = version;
+ int line = document.getLineOfOffset(off.getStartOffset());
+ try {
+ int lineend = document.getLineOffset(line) + document.getLineLength(line) - 1;
+ int start = off.getStartOffset();
+ while (reg != null && start < lineend) {
+ reg = reg.getNextSibling();
+ if (reg != null && reg instanceof Comment) {
+ Comment comm = (Comment)reg;
+ String data =comm.getData();
+ if (data != null && data.contains(ignoreString)) {
+ return true;
+ }
+ }
+ if (reg != null) {
+ start = ((IndexedRegion)reg).getStartOffset();
+ }
+ }
+ } catch(BadLocationException ex) {
+ //not possible IMHO we ask for line offset of line we know is in the document.
+ }
+ return false;
+ }
+
+ private void checkManagedPlugins(Element root, IResource pomFile, String type, IStructuredDocument document)
+ throws CoreException {
+ IProject prj = pomFile.getProject();
+ //the project returned is in a way unrelated to nested child poms that don't have an opened project,
+ //in that case we pass along a wrong parent/aggregator
+ if (prj == null || pomFile.getProjectRelativePath().segmentCount() != 1) {
+ //if the project were the pom's project, the relative path would be just "pom.xml", if it's not just throw it out of the window..
+ return;
+ }
+ IMavenProjectFacade facade = MavenPlugin.getDefault().getMavenProjectManager().getProject(prj);
+ if (facade == null) {
+ return;
+ }
+ MavenProject mavenproject = facade.getMavenProject();
+ if (mavenproject == null) {
+ //we only work with cached instances here, never loading ourselves..
+ return;
+ }
+ List<Element> candidates = new ArrayList<Element>();
+ Element build = findChildElement(root, "build"); //$NON-NLS-1$
+ if (build == null) {
+ return;
+ }
+ Element plugins = findChildElement(build, "plugins"); //$NON-NLS-1$
+ if (plugins != null) {
+ for (Element el : findChildElements(plugins, "plugin")) { //$NON-NLS-1$
+ Element version = findChildElement(el, "version"); //$NON-NLS-1$
+ if (version != null) {
+ candidates.add(el);
+ }
+ }
+ }
+ //we should also consider <plugins> section in the profiles, but profile are optional and so is their
+ // pluginManagement section.. that makes handling our markers more complex.
+ // see MavenProject.getInjectedProfileIds() for a list of currently active profiles in effective pom
+ String currentProjectKey = mavenproject.getGroupId() + ":" + mavenproject.getArtifactId() + ":" + mavenproject.getVersion(); //$NON-NLS-1$ //$NON-NLS-2$
+ List<String> activeprofiles = mavenproject.getInjectedProfileIds().get(currentProjectKey);
+ //remember what profile we found the dependency in.
+ Map<Element, String> candidateProfile = new HashMap<Element, String>();
+ Element profiles = findChildElement(root, "profiles"); //$NON-NLS-1$
+ if (profiles != null) {
+ for (Element profile : findChildElements(profiles, "profile")) { //$NON-NLS-1$
+ String idString = getElementTextValue(findChildElement(profile, "id")); //$NON-NLS-1$
+ if (idString != null && activeprofiles.contains(idString)) {
+ build = findChildElement(profile, "build"); //$NON-NLS-1$
+ if (build == null) {
+ continue;
+ }
+ plugins = findChildElement(build, "plugins"); //$NON-NLS-1$
+ if (plugins != null) {
+ for (Element el : findChildElements(plugins, "plugin")) { //$NON-NLS-1$
+ Element version = findChildElement(el, "version"); //$NON-NLS-1$
+ if (version != null) {
+ candidates.add(el);
+ candidateProfile.put(el, idString);
+ }
+ }
+ }
+ }
+ }
+ }
+ //collect the managed plugin ids
+ Map<String, String> managed = new HashMap<String, String>();
+ PluginManagement pm = mavenproject.getPluginManagement();
+ if (pm != null) {
+ List<Plugin> plgs = pm.getPlugins();
+ if (plgs != null) {
+ for (Plugin plg : plgs) {
+ managed.put(plg.getKey(), plg.getVersion());
+ }
+ }
+ }
+
+ //now we have all the candidates, match them against the effective managed set
+ for(Element dep : candidates) {
+ String grpString = getElementTextValue(findChildElement(dep, "groupId")); //$NON-NLS-1$
+ if (grpString == null) {
+ grpString = "org.apache.maven.plugins"; //$NON-NLS-1$
+ }
+ String artString = getElementTextValue(findChildElement(dep, "artifactId")); //$NON-NLS-1$
+ Element version = findChildElement(dep, "version"); //$NON-NLS-1$
+ String versionString = getElementTextValue(version);
+ if(grpString != null && artString != null && versionString != null) {
+ String id = Plugin.constructKey(grpString, artString);
+ if(managed.containsKey(id)) {
+ String managedVersion = managed.get(id);
+ if(version instanceof IndexedRegion) {
+ IndexedRegion off = (IndexedRegion) version;
+ if(lookForIgnoreMarker(document, version, off, IMavenConstants.MARKER_IGNORE_MANAGED)) {
+ continue;
+ }
+
+ IMarker mark = addMarker(pomFile, type, NLS.bind(
+ org.eclipse.m2e.core.internal.Messages.MavenMarkerManager_managed_title, managedVersion, artString),
+ document.getLineOfOffset(off.getStartOffset()) + 1, IMarker.SEVERITY_WARNING, false /*isTransient*/);
+ mark.setAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT,
+ IMavenConstants.EDITOR_HINT_MANAGED_PLUGIN_OVERRIDE);
+ mark.setAttribute(IMarker.CHAR_START, off.getStartOffset());
+ mark.setAttribute(IMarker.CHAR_END, off.getEndOffset());
+ mark.setAttribute("problemType", "pomhint"); //only imporant in case we enable the generic xml quick fixes //$NON-NLS-1$ //$NON-NLS-2$
+ //add these attributes to easily and deterministicaly find the declaration in question
+ mark.setAttribute("groupId", grpString); //$NON-NLS-1$
+ mark.setAttribute("artifactId", artString); //$NON-NLS-1$
+ String profile = candidateProfile.get(dep);
+ if(profile != null) {
+ mark.setAttribute("profile", profile); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void checkParentMatchingGroupIdVersion(Element root, IResource pomFile, String type,
+ IStructuredDocument document) throws CoreException {
+ Element parent = findChildElement(root, "parent"); //$NON-NLS-1$
+ Element groupId = findChildElement(root, "groupId"); //$NON-NLS-1$
+ if(parent != null && groupId != null) {
+ //now compare the values of parent and project groupid..
+ String parentString = getElementTextValue(findChildElement(parent, "groupId")); //$NON-NLS-1$
+ String childString = getElementTextValue(groupId);
+ if(parentString != null && parentString.equals(childString)) {
+ //now figure out the offset
+ if(groupId instanceof IndexedRegion) {
+ IndexedRegion off = (IndexedRegion) groupId;
+ IMarker mark = addMarker(pomFile, type,
+ org.eclipse.m2e.core.internal.Messages.MavenMarkerManager_duplicate_groupid,
+ document.getLineOfOffset(off.getStartOffset()) + 1, IMarker.SEVERITY_WARNING, false /*isTransient*/);
+ mark.setAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT, IMavenConstants.EDITOR_HINT_PARENT_GROUP_ID);
+ mark.setAttribute(IMarker.CHAR_START, off.getStartOffset());
+ mark.setAttribute(IMarker.CHAR_END, off.getEndOffset());
+ mark.setAttribute("problemType", "pomhint"); //only important in case we enable the generic xml quick fixes //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+ Element version = findChildElement(root, "version"); //$NON-NLS-1$
+ if(parent != null && version != null) {
+ //now compare the values of parent and project version..
+ String parentString = getElementTextValue(findChildElement(parent, "version")); //$NON-NLS-1$
+ String childString = getElementTextValue(version);
+ if(parentString != null && parentString.equals(childString)) {
+ //now figure out the offset
+ if(version instanceof IndexedRegion) {
+ IndexedRegion off = (IndexedRegion) version;
+ IMarker mark = addMarker(pomFile, type,
+ org.eclipse.m2e.core.internal.Messages.MavenMarkerManager_duplicate_version,
+ document.getLineOfOffset(off.getStartOffset()) + 1, IMarker.SEVERITY_WARNING, false);
+ mark.setAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT, IMavenConstants.EDITOR_HINT_PARENT_VERSION);
+ mark.setAttribute(IMarker.CHAR_START, off.getStartOffset());
+ mark.setAttribute(IMarker.CHAR_END, off.getEndOffset());
+ mark.setAttribute("problemType", "pomhint"); //only important in case we enable the generic xml quick fixes //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+ }
+
+ public static Element findChildElement(Element parent, String name) {
+ NodeList rootList = parent.getChildNodes();
+ for (int i = 0; i < rootList.getLength(); i++) {
+ Node nd = rootList.item(i);
+ if (nd instanceof Element) {
+ Element el = (Element)nd;
+ if (name.equals(el.getNodeName())) {
+ return el;
+ }
+ }
+ }
+ return null;
+ }
+ public static List<Element> findChildElements(Element parent, String name) {
+ NodeList rootList = parent.getChildNodes();
+ List<Element> toRet = new ArrayList<Element>();
+ for (int i = 0; i < rootList.getLength(); i++) {
+ Node nd = rootList.item(i);
+ if (nd instanceof Element) {
+ Element el = (Element)nd;
+ if (name.equals(el.getNodeName())) {
+ toRet.add(el);
+ }
+ }
+ }
+ return toRet;
+ }
+
+ /**
+ * gets the element text value, accepts null as parameter
+ * @param element
+ * @return
+ */
+ public static String getElementTextValue(Node element) {
+ if (element == null) return null;
+ StringBuffer buff = new StringBuffer();
+ NodeList list = element.getChildNodes();
+ for (int i = 0; i < list.getLength(); i++) {
+ Node child = list.item(i);
+ if (child instanceof Text) {
+ Text text = (Text)child;
+ buff.append(text.getData());
+ }
+ }
+ return buff.toString();
+ }
+
+ /**
+ * The xsi:schema info is not part of the model, it is stored in the xml only. Need to open the DOM
+ * and look for the project node to see if it has this schema defined
+ * @param pomFile
+ */
+ protected void checkForSchema(IResource pomFile, String type) {
+ IDOMModel domModel = null;
+ try{
+ if(!(pomFile instanceof IFile)){
+ return;
+ }
+ domModel = (IDOMModel)StructuredModelManager.getModelManager().getModelForRead((IFile)pomFile);
+ IStructuredDocument document = domModel.getStructuredDocument();
+
+ // iterate through document regions
+ documentLoop:for(IStructuredDocumentRegion documentRegion : document.getStructuredDocumentRegions()) {
+ // only check tag regions
+ if (DOMRegionContext.XML_TAG_NAME.equals(documentRegion.getType())){
+ for(ITextRegion textRegion: documentRegion.getRegions().toArray()){
+ // find a project tag
+ if(textRegion instanceof TagNameRegion && PROJECT_NODE.equals(documentRegion.getText(textRegion))){
+ // check if schema is missing
+ if (documentRegion.getText().lastIndexOf(XSI_SCHEMA_LOCATION) == -1) {
+ int offset = documentRegion.getStartOffset();
+ int lineNumber = document.getLineOfOffset(offset) + 1;
+ IMarker marker = addMarker(pomFile, type,
+ org.eclipse.m2e.core.internal.Messages.MavenMarkerManager_error_noschema, lineNumber,
+ IMarker.SEVERITY_WARNING, false /*isTransient*/);
+ //the quick fix in the marker view needs to know the offset, since it doesn't have access to the
+ //editor/source viewer
+ if(marker != null){
+ marker.setAttribute(OFFSET, offset);
+ marker.setAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT,
+ IMavenConstants.EDITOR_HINT_MISSING_SCHEMA);
+ marker.setAttribute(IMarker.CHAR_START, documentRegion.getStartOffset());
+ marker.setAttribute(IMarker.CHAR_END, documentRegion.getEndOffset());
+ marker.setAttribute("problemType", "pomhint"); //only imporant in case we enable the generic xml quick fixes //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ // there could only be one project tag
+ break documentLoop;
+ }
+ }
+ }
+ }
+ } catch(Exception ex) {
+ MavenLogger.log("Error checking for schema", ex); //$NON-NLS-1$
+ }
+ finally {
+ if ( domModel != null ) {
+ domModel.releaseFromRead();
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.core.project.IMavenMarkerManager#addMarker(org.eclipse.core.resources.IResource, java.lang.String, int, int)
+ */
+ //just here to satisfy the IMavenMarkerManager contract.
+ public IMarker addMarker(IResource resource, String type, String message, int lineNumber, int severity) {
+ return addMarker(resource, type, message, lineNumber, severity, false /*isTransient*/);
+ }
+
+ private IMarker addMarker(IResource resource, String type, String message, int lineNumber, int severity, boolean isTransient) {
+ IMarker marker = null;
+ try {
+ if(resource.isAccessible()) {
+ marker = findMarker(resource, type, message, lineNumber, severity, isTransient);
+ if(marker != null) {
+ // This marker already exists
+ return marker;
+ }
+ marker= resource.createMarker(type);
+ marker.setAttribute(IMarker.MESSAGE, message);
+ marker.setAttribute(IMarker.SEVERITY, severity);
+ marker.setAttribute(IMarker.TRANSIENT, isTransient);
+
+ if(lineNumber == -1) {
+ lineNumber = 1;
+ }
+ marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
+ }
+ } catch(CoreException ex) {
+ console.logError("Unable to add marker; " + ex.toString()); //$NON-NLS-1$
+ }
+ return marker;
+ }
+
+ private static <T> boolean eq(T a, T b) {
+ if(a == null) {
+ if(b == null) {
+ return true;
+ }
+ return false;
+ }
+ return a.equals(b);
+ }
+
+ private IMarker findMarker(IResource resource, String type, String message, int lineNumber, int severity,
+ boolean isTransient) throws CoreException {
+ IMarker[] markers = resource.findMarkers(type, false /*includeSubtypes*/, IResource.DEPTH_ZERO);
+ if(markers == null || markers.length == 0) {
+ return null;
+ }
+ for(IMarker marker : markers) {
+ if(eq(message, marker.getAttribute(IMarker.MESSAGE)) && eq(lineNumber, marker.getAttribute(IMarker.LINE_NUMBER))
+ && eq(severity, marker.getAttribute(IMarker.SEVERITY))
+ && eq(isTransient, marker.getAttribute(IMarker.TRANSIENT))) {
+ return marker;
+ }
+ }
+ return null;
+ }
+
+ private void handleProjectBuildingException(IResource pomFile, String type, ProjectBuildingException ex) {
+ Throwable cause = ex.getCause();
+ if(cause instanceof ModelBuildingException) {
+ ModelBuildingException mbe = (ModelBuildingException) cause;
+ for (ModelProblem problem : mbe.getProblems()) {
+ String msg = Messages.getString("plugin.markerBuildError", problem.getMessage()); //$NON-NLS-1$
+// console.logError(msg);
+ int severity = (Severity.WARNING == problem.getSeverity())? IMarker.SEVERITY_WARNING: IMarker.SEVERITY_ERROR;
+ addMarker(pomFile, type, msg, 1, severity);
+ }
+ } else {
+ handleBuildException(pomFile, type, ex);
+ }
+ }
+
+ private void handleBuildException(IResource pomFile, String type, Throwable ex) {
+ Throwable cause = getRootCause(ex);
+ // String msg = Messages.getString("plugin.markerBuildError", cause.getMessage()); //$NON-NLS-1$
+ String msg = cause.getMessage();
+ addMarker(pomFile, type, msg, 1, IMarker.SEVERITY_ERROR);
+// console.logError(msg);
+ }
+
+ private String getArtifactId(AbstractArtifactResolutionException rex) {
+ String id = rex.getGroupId() + ":" + rex.getArtifactId() + ":" + rex.getVersion(); //$NON-NLS-1$ //$NON-NLS-2$
+ if(rex.getClassifier() != null) {
+ id += ":" + rex.getClassifier(); //$NON-NLS-1$
+ }
+ if(rex.getType() != null) {
+ id += ":" + rex.getType(); //$NON-NLS-1$
+ }
+ return id;
+ }
+
+ private String getErrorMessage(Throwable ex) {
+ return getRootCause(ex).getMessage();
+ }
+
+ private Throwable getRootCause(Throwable ex) {
+ Throwable lastCause = ex;
+ Throwable cause = lastCause.getCause();
+ while(cause != null && cause != lastCause) {
+ if(cause instanceof ArtifactNotFoundException) {
+ cause = null;
+ } else {
+ lastCause = cause;
+ cause = cause.getCause();
+ }
+ }
+ return cause == null ? lastCause : cause;
+ }
+
+
+ private void addErrorMarkers(IResource pomFile, String type, String msg, List<? extends Exception> exceptions) {
+ if(exceptions != null) {
+ for(Exception ex : exceptions) {
+ if(ex instanceof org.sonatype.aether.transfer.ArtifactNotFoundException) {
+ // ignored here, handled by addMissingArtifactMarkers
+ } else if(ex instanceof AbstractArtifactResolutionException) {
+ AbstractArtifactResolutionException rex = (AbstractArtifactResolutionException) ex;
+ String errorMessage = getArtifactId(rex) + " " + getErrorMessage(ex); //$NON-NLS-1$
+ addMarker(pomFile, type, errorMessage, 1, IMarker.SEVERITY_ERROR);
+// console.logError(errorMessage);
+
+ } else {
+ addMarker(pomFile, type, ex.getMessage(), 1, IMarker.SEVERITY_ERROR);
+// console.logError(msg + "; " + ex.toString());
+ }
+ }
+ }
+ }
+
+ public void deleteMarkers(IResource resource, String type) throws CoreException {
+ if (resource != null && resource.exists()) {
+ resource.deleteMarkers(type, true, IResource.DEPTH_INFINITE);
+ }
+ }
+
+ private void addMissingArtifactMarkers(IResource pomFile, String type, MavenProject mavenProject) {
+// Set<Artifact> directDependencies = mavenProject.getDependencyArtifacts();
+ Set<Artifact> artifacts = mavenProject.getArtifacts();
+ for(Artifact artifact : artifacts) {
+ if (!artifact.isResolved()) {
+ String errorMessage;
+// if (directDependencies.contains(artifact)) {
+ errorMessage = NLS.bind(org.eclipse.m2e.core.internal.Messages.MavenMarkerManager_error_missing, artifact.toString());
+// } else {
+// errorMessage = "Missing indirectly referenced artifact " + artifact.toString();
+// }
+
+ if(mavenConfiguration.isOffline()) {
+ errorMessage = NLS.bind(org.eclipse.m2e.core.internal.Messages.MavenMarkerManager_error_offline, errorMessage);
+ }
+
+ addMarker(pomFile, type, errorMessage, 1, IMarker.SEVERITY_ERROR);
+ console.logError(errorMessage);
+ }
+ }
+ }
+
+ public void addErrorMarkers(IResource resource, String type, Exception ex) {
+ Throwable cause = getRootCause(ex);
+ if(cause instanceof CoreException) {
+ CoreException cex = (CoreException) cause;
+ IStatus status = cex.getStatus();
+ if(status != null) {
+ addMarker(resource, type, status.getMessage(), 1, IMarker.SEVERITY_ERROR, false /*isTransient*/); //$NON-NLS-1$
+ IStatus[] children = status.getChildren();
+ if(children != null) {
+ for(IStatus childStatus : children) {
+ addMarker(resource, type, childStatus.getMessage(), 1, IMarker.SEVERITY_ERROR, false /*isTransient*/); //$NON-NLS-1$
+ }
+ }
+ }
+ } else {
+ addMarker(resource, type, cause.getMessage(), 1, IMarker.SEVERITY_ERROR, false /*isTransient*/); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MavenProjectImportResult.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MavenProjectImportResult.java
new file mode 100644
index 00000000..68d6a628
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MavenProjectImportResult.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import org.eclipse.core.resources.IProject;
+
+import org.eclipse.m2e.core.project.IMavenProjectImportResult;
+import org.eclipse.m2e.core.project.MavenProjectInfo;
+
+public class MavenProjectImportResult implements IMavenProjectImportResult {
+
+ private final IProject project;
+ private final MavenProjectInfo projectInfo;
+
+ public MavenProjectImportResult(MavenProjectInfo projectInfo, IProject project) {
+ this.projectInfo = projectInfo;
+ this.project = project;
+ }
+
+ public IProject getProject() {
+ return project;
+ }
+
+ public MavenProjectInfo getMavenProjectInfo() {
+ return projectInfo;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MissingLifecycleMapping.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MissingLifecycleMapping.java
new file mode 100644
index 00000000..cff8e77a
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MissingLifecycleMapping.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.plugin.MojoExecution;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.configurator.AbstractBuildParticipant;
+import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator;
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+import org.eclipse.m2e.core.project.configurator.ProjectConfigurationRequest;
+
+
+/**
+ * MissingLifecycleMapping
+ *
+ * @author igor
+ */
+public class MissingLifecycleMapping implements ILifecycleMapping {
+
+ /**
+ * Lifecycle mapping id. Must match id of properties page defined in plugin.xml
+ */
+ public static final String ID = "MISSING"; //$NON-NLS-1$
+
+ private final String missingMappingId;
+
+ public MissingLifecycleMapping(String mappingId) {
+ this.missingMappingId = mappingId;
+ }
+
+ public String getId() {
+ return ID;
+ }
+
+ public String getName() {
+ return Messages.MissingLifecycleMapping_name;
+ }
+
+ public List<String> getPotentialMojoExecutionsForBuildKind(IMavenProjectFacade projectFacade, int kind,
+ IProgressMonitor progressMonitor) {
+ return Collections.emptyList();
+ }
+
+ public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) {
+ }
+
+ public void unconfigure(ProjectConfigurationRequest request, IProgressMonitor monitor) {
+ }
+
+ public List<AbstractBuildParticipant> getBuildParticipants(IMavenProjectFacade facade, IProgressMonitor monitor) {
+ return Collections.emptyList();
+ }
+
+ public List<AbstractProjectConfigurator> getProjectConfigurators(IMavenProjectFacade facade, IProgressMonitor monitor) {
+ return Collections.emptyList();
+ }
+
+ public String getMissingMappingId() {
+ return missingMappingId;
+ }
+
+ public List<MojoExecution> getNotCoveredMojoExecutions(IMavenProjectFacade mavenProjectFacade,
+ IProgressMonitor monitor) throws CoreException {
+ return Collections.emptyList();
+ }
+
+ public boolean isInterestingPhase(String phase) {
+ return false;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MojoExecutionProjectConfigurator.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MojoExecutionProjectConfigurator.java
new file mode 100644
index 00000000..b71b4108
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MojoExecutionProjectConfigurator.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.plugin.MojoExecution;
+
+import org.eclipse.m2e.core.project.configurator.AbstractBuildParticipant;
+import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator;
+import org.eclipse.m2e.core.project.configurator.MojoExecutionBuildParticipant;
+import org.eclipse.m2e.core.project.configurator.ProjectConfigurationRequest;
+
+
+/**
+ * MojoExecutionProjectConfigurator
+ *
+ * @author igor
+ */
+public class MojoExecutionProjectConfigurator extends AbstractProjectConfigurator {
+
+ private final boolean runOnIncremental;
+
+ public MojoExecutionProjectConfigurator(boolean runOnIncremental) {
+ this.runOnIncremental = runOnIncremental;
+ }
+
+ protected MojoExecutionProjectConfigurator(String groupId, String artifactId, String versionRange, String goals,
+ boolean runOnIncremental) {
+ this.runOnIncremental = runOnIncremental;
+
+ addPluginExecutionFilter(groupId, artifactId, versionRange, goals);
+ }
+
+ public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) {
+ // do nothing
+ }
+
+ public AbstractBuildParticipant getBuildParticipant(MojoExecution execution) {
+ return new MojoExecutionBuildParticipant(execution, runOnIncremental);
+ }
+
+ public static MojoExecutionProjectConfigurator fromString(String str, boolean runOnIncremental) {
+ if(str == null || str.trim().length() <= 0) {
+ return null;
+ }
+
+ int p, c;
+
+ p = 0;
+ c = nextColonIndex(str, p);
+ String groupId = substring(str, p, c);
+
+ p = c + 1;
+ c = nextColonIndex(str, p);
+ String artifactId = substring(str, p, c);
+
+ p = c + 1;
+ c = nextColonIndex(str, p);
+ String versionRange = substring(str, p, c);
+
+ p = c + 1;
+ String goals = substring(str, p, str.length());
+
+ return new MojoExecutionProjectConfigurator(groupId, artifactId, versionRange, goals, runOnIncremental);
+ }
+
+ private static String substring(String str, int start, int end) {
+ String substring = str.substring(start, end);
+ return "".equals(substring) ? null : substring; //$NON-NLS-1$
+ }
+
+ private static int nextColonIndex(String str, int pos) {
+ int idx = str.indexOf(':', pos);
+ if(idx < 0) {
+ throw new IllegalArgumentException("Invalid mojo execution template: " + str);
+ }
+ return idx;
+ }
+
+ public String getName() {
+ return "execute";
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MojoExecutionUtils.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MojoExecutionUtils.java
new file mode 100644
index 00000000..d6a5bda5
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/MojoExecutionUtils.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import org.apache.maven.plugin.MojoExecution;
+
+/**
+ * MavenExecutionUtils
+ *
+ * @author mpoindexter
+ */
+public class MojoExecutionUtils {
+ public static String getExecutionKey(MojoExecution execution) {
+ return nvl(execution.getGroupId()) + ":" + nvl(execution.getArtifactId()) + ":" + nvl(execution.getVersion()) + ":" + nvl(execution.getGoal()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ private static String nvl(String s) {
+ return s == null ? "" : s; //$NON-NLS-1$
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ProjectConfigurationManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ProjectConfigurationManager.java
new file mode 100644
index 00000000..1c48f23b
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/ProjectConfigurationManager.java
@@ -0,0 +1,716 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+
+import org.eclipse.core.resources.ICommand;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IWorkingSet;
+
+import org.codehaus.plexus.util.StringUtils;
+
+import org.apache.maven.archetype.ArchetypeGenerationRequest;
+import org.apache.maven.archetype.ArchetypeGenerationResult;
+import org.apache.maven.archetype.catalog.Archetype;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Model;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory.RemoteCatalogFactory;
+import org.eclipse.m2e.core.archetype.ArchetypeManager;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.embedder.MavenModelManager;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.IMavenMarkerManager;
+import org.eclipse.m2e.core.project.IMavenProjectChangedListener;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.IMavenProjectImportResult;
+import org.eclipse.m2e.core.project.IProjectConfigurationManager;
+import org.eclipse.m2e.core.project.LocalProjectScanner;
+import org.eclipse.m2e.core.project.MavenProjectChangedEvent;
+import org.eclipse.m2e.core.project.MavenProjectInfo;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.project.MavenUpdateRequest;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+import org.eclipse.m2e.core.project.ResolverConfiguration;
+import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator;
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+import org.eclipse.m2e.core.project.configurator.ProjectConfigurationRequest;
+import org.eclipse.m2e.core.util.Util;
+
+/**
+ * import Maven projects
+ * update project configuration from Maven
+ * enable Maven nature
+ * create new project
+ *
+ * @author igor
+ */
+public class ProjectConfigurationManager implements IProjectConfigurationManager, IMavenProjectChangedListener {
+
+ final MavenConsole console;
+
+ final MavenProjectManager projectManager;
+
+ final MavenModelManager mavenModelManager;
+
+ final IMavenMarkerManager mavenMarkerManager;
+
+ final IMaven maven;
+
+ final IMavenConfiguration mavenConfiguration;
+
+ public ProjectConfigurationManager(IMaven maven, MavenConsole console, MavenProjectManager projectManager,
+ MavenModelManager mavenModelManager, IMavenMarkerManager mavenMarkerManager, IMavenConfiguration mavenConfiguration) {
+ this.console = console;
+ this.projectManager = projectManager;
+ this.mavenModelManager = mavenModelManager;
+ this.mavenMarkerManager = mavenMarkerManager;
+ this.maven = maven;
+ this.mavenConfiguration = mavenConfiguration;
+ }
+
+ public List<IMavenProjectImportResult> importProjects(Collection<MavenProjectInfo> projectInfos, ProjectImportConfiguration configuration, IProgressMonitor monitor) throws CoreException {
+ long t1 = System.currentTimeMillis();
+
+ SubMonitor progress = SubMonitor.convert(monitor, Messages.ProjectConfigurationManager_task_importing, 100);
+
+ ArrayList<IMavenProjectImportResult> result = new ArrayList<IMavenProjectImportResult>();
+ ArrayList<IProject> projects = new ArrayList<IProject>();
+
+ SubMonitor subProgress =
+ SubMonitor.convert( progress.newChild( 10 ), projectInfos.size() * 100 );
+
+ // first, create all projects with basic configuration
+ for(MavenProjectInfo projectInfo : projectInfos) {
+ if(monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+
+ IProject project = create(projectInfo, configuration, subProgress.newChild(100));
+
+ result.add(new MavenProjectImportResult(projectInfo, project));
+
+ if (project != null) {
+ projects.add(project);
+
+ addToWorkingSets(project, configuration.getWorkingSets());
+ }
+ }
+
+ hideNestedProjectsFromParents(projects);
+ // then configure maven for all projects
+ configureNewMavenProject(projects, progress.newChild(90));
+
+ long t2 = System.currentTimeMillis();
+ console.logMessage("Project import completed " + ((t2 - t1) / 1000) + " sec");
+
+ return result;
+ }
+
+
+ private void setHidden(IResource resource) {
+ // Invoke IResource.setHidden() through reflection since it is only avaiable in Eclispe 3.4 & later
+ try {
+ Method m = IResource.class.getMethod("setHidden", boolean.class); //$NON-NLS-1$
+ m.invoke(resource, Boolean.TRUE);
+ } catch (Exception ex) {
+ MavenLogger.log("Failed to hide resource; " + resource.getLocation().toOSString(), ex);
+ }
+ }
+
+ private void hideNestedProjectsFromParents(List<IProject> projects) {
+
+ if (!MavenPlugin.getDefault().getMavenConfiguration().isHideFoldersOfNestedProjects()) {
+ return;
+ }
+ // Prevent child project folders from showing up in parent project folders.
+
+ Bundle bundle = ResourcesPlugin.getPlugin().getBundle();
+ String version = (String) bundle.getHeaders().get(org.osgi.framework.Constants.BUNDLE_VERSION);
+ Version currentVersion = org.osgi.framework.Version.parseVersion(version);
+ Version e34Version = new Version(3,4,0);
+ if (currentVersion.compareTo(e34Version) < 0) {
+ return; // IResource.setHidden doesn't exist in Eclipse prior to version 3.4
+ }
+ HashMap<File, IProject> projectFileMap = new HashMap<File, IProject>();
+
+ for (IProject project: projects) {
+ projectFileMap.put(project.getLocation().toFile(), project);
+ }
+ for (IProject project: projects) {
+ File projectFile = project.getLocation().toFile();
+ IProject physicalParentProject = projectFileMap.get(projectFile.getParentFile());
+ if (physicalParentProject == null) {
+ continue;
+ }
+ IFolder folder = physicalParentProject.getFolder(projectFile.getName());
+ if (folder.exists()) {
+ setHidden(folder);
+ }
+ }
+ }
+
+ private void configureNewMavenProject(List<IProject> projects, IProgressMonitor monitor)
+ throws CoreException {
+ SubMonitor progress = SubMonitor.convert(monitor, Messages.ProjectConfigurationManager_task_configuring, 100);
+
+ //SubProgressMonitor sub = new SubProgressMonitor(monitor, projects.size()+1);
+
+ // first, resolve maven dependencies for all projects
+ MavenUpdateRequest updateRequest = new MavenUpdateRequest(mavenConfiguration.isOffline(), false);
+ for(IProject project : projects) {
+ updateRequest.addPomFile(project);
+ }
+ progress.subTask(Messages.ProjectConfigurationManager_task_refreshing);
+ projectManager.refresh(updateRequest, progress.newChild(75));
+
+ // TODO this emits project change events, which may be premature at this point
+
+ //Creating maven facades
+ SubMonitor subProgress = SubMonitor.convert(progress.newChild(5), projects.size() * 100);
+ List<IMavenProjectFacade> facades = new ArrayList<IMavenProjectFacade>(projects.size());
+ for(IProject project : projects) {
+ if(progress.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ IMavenProjectFacade facade = projectManager.create(project, subProgress.newChild(100));
+ if (facade != null) {
+ facades.add(facade);
+ }
+ }
+
+ //MNGECLIPSE-1028 : Sort projects by build order here,
+ //as dependent projects need to be configured before depending projects (in WTP integration for ex.)
+ sortProjects(facades, progress.newChild(5));
+ //Then, perform detailed project configuration
+ subProgress = SubMonitor.convert(progress.newChild(15), facades.size() * 100);
+ for(IMavenProjectFacade facade : facades) {
+ if(progress.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ progress.subTask(NLS.bind(Messages.ProjectConfigurationManager_task_updating, facade.getProject().getName()));
+ MavenProject mavenProject = facade.getMavenProject(subProgress.newChild(5));
+ MavenSession mavenSession = createMavenSession(facade, subProgress.newChild(5));
+ ProjectConfigurationRequest request = new ProjectConfigurationRequest(facade, mavenProject, mavenSession, false /*updateSources*/);
+ updateProjectConfiguration(request, subProgress.newChild(90));
+ }
+ }
+
+ private MavenSession createMavenSession(IMavenProjectFacade facade, IProgressMonitor monitor) throws CoreException {
+ MavenExecutionRequest request = projectManager.createExecutionRequest(facade.getPom(), facade.getResolverConfiguration(), monitor);
+ return maven.createSession(request, facade.getMavenProject(monitor));
+ }
+
+ public void sortProjects(List<IMavenProjectFacade> facades, IProgressMonitor monitor) throws CoreException {
+ HashMap<MavenProject, IMavenProjectFacade> mavenProjectToFacadeMap = new HashMap<MavenProject, IMavenProjectFacade>(facades.size());
+ for(IMavenProjectFacade facade:facades) {
+ mavenProjectToFacadeMap.put(facade.getMavenProject(monitor), facade);
+ }
+ facades.clear();
+ for(MavenProject mavenProject: maven.getSortedProjects(new ArrayList<MavenProject>(mavenProjectToFacadeMap.keySet()))) {
+ facades.add(mavenProjectToFacadeMap.get(mavenProject));
+ }
+ }
+
+ // PlatformUI.getWorkbench().getWorkingSetManager().addToWorkingSets(project, new IWorkingSet[] {workingSet});
+ private void addToWorkingSets(IProject project, IWorkingSet[] workingSets) {
+ if (workingSets != null && workingSets.length > 0) {
+ // IAdaptable[] elements = workingSet.adaptElements(new IAdaptable[] {project});
+ // if(elements.length == 1) {
+ for (IWorkingSet workingSet : workingSets) {
+ IAdaptable[] oldElements = workingSet.getElements();
+ IAdaptable[] newElements = new IAdaptable[oldElements.length + 1];
+ System.arraycopy(oldElements, 0, newElements, 0, oldElements.length);
+ newElements[oldElements.length] = project;
+
+ // Eclipse 3.2 compatibility
+ workingSet.setElements(Util.proxy(workingSet, A.class).adaptElements(newElements));
+ // }
+ }
+ }
+ }
+
+ /**
+ * A compatibility proxy stub
+ */
+ private static interface A {
+ public IAdaptable[] adaptElements(IAdaptable[] objects);
+ }
+
+ public void updateProjectConfiguration(IProject project, ResolverConfiguration configuration, IProgressMonitor monitor) throws CoreException {
+ IFile pom = project.getFile(IMavenConstants.POM_FILE_NAME);
+ if (pom.isAccessible()) {
+ projectManager.refresh(new MavenUpdateRequest(project, mavenConfiguration.isOffline(), false), monitor);
+ IMavenProjectFacade facade = projectManager.create(pom, false, monitor);
+ if (facade != null) { // facade is null if pom.xml cannot be read
+ ProjectConfigurationRequest request = new ProjectConfigurationRequest(facade, facade.getMavenProject(monitor), createMavenSession(facade, monitor), true /*updateSources*/);
+ updateProjectConfiguration(request, monitor);
+ }
+ }
+ }
+
+ private void updateProjectConfiguration(ProjectConfigurationRequest request,
+ IProgressMonitor monitor) throws CoreException {
+ IProject project = request.getProject();
+ addMavenNature(project, monitor);
+
+ IMavenProjectFacade mavenProjectFacade = request.getMavenProjectFacade();
+ validateProjectConfiguration(mavenProjectFacade, monitor);
+
+ ILifecycleMapping lifecycleMapping = getLifecycleMapping(mavenProjectFacade, monitor);
+ lifecycleMapping.configure(request, monitor);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.core.project.IProjectConfigurationManager#validateProjectConfiguration(org.eclipse.m2e.core.project.IMavenProjectFacade, org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public boolean validateProjectConfiguration(IMavenProjectFacade mavenProjectFacade, IProgressMonitor monitor) {
+ try {
+ mavenProjectFacade.setHasValidConfiguration(false);
+ mavenMarkerManager.deleteMarkers(mavenProjectFacade.getPom(), IMavenConstants.MARKER_CONFIGURATION_ID);
+
+ ILifecycleMapping lifecycleMapping = getLifecycleMapping(mavenProjectFacade, monitor);
+ if(lifecycleMapping == null || lifecycleMapping instanceof MissingLifecycleMapping) {
+ String lifecycleId = null;
+ if(lifecycleMapping != null) {
+ lifecycleId = lifecycleMapping.getId();
+ }
+ mavenMarkerManager.addMarker(mavenProjectFacade.getPom(), IMavenConstants.MARKER_CONFIGURATION_ID,
+ NLS.bind(Messages.LifecycleMissing, lifecycleId, mavenProjectFacade.getPackaging()), 1 /*lineNumber*/,
+ IMarker.SEVERITY_ERROR);
+ return false;
+ }
+
+ List<MojoExecution> notCoveredMojoExecutions = lifecycleMapping.getNotCoveredMojoExecutions(mavenProjectFacade,
+ monitor);
+ if(notCoveredMojoExecutions != null && notCoveredMojoExecutions.size() != 0) {
+ for(MojoExecution mojoExecution : notCoveredMojoExecutions) {
+ mavenMarkerManager.addMarker(
+ mavenProjectFacade.getPom(),
+ IMavenConstants.MARKER_CONFIGURATION_ID,
+ NLS.bind(Messages.LifecycleConfigurationMojoExecutionNotCovered, mojoExecution.toString(),
+ mojoExecution.getLifecyclePhase()), 1 /*lineNumber*/, IMarker.SEVERITY_ERROR);
+ }
+ return false;
+ }
+ mavenProjectFacade.setHasValidConfiguration(true);
+ return true;
+ } catch(CoreException e) {
+ mavenMarkerManager.addErrorMarkers(mavenProjectFacade.getPom(), IMavenConstants.MARKER_CONFIGURATION_ID, e);
+ return false;
+ }
+ }
+
+ public void enableMavenNature(IProject project, ResolverConfiguration configuration, IProgressMonitor monitor)
+ throws CoreException {
+ monitor.subTask(Messages.ProjectConfigurationManager_task_enable_nature);
+ enableBasicMavenNature(project, configuration, monitor);
+
+ ArrayList<IProject> projects = new ArrayList<IProject>();
+ projects.add(project);
+ configureNewMavenProject(projects, monitor);
+ }
+
+ private void enableBasicMavenNature(IProject project, ResolverConfiguration configuration, IProgressMonitor monitor)
+ throws CoreException {
+ projectManager.setResolverConfiguration(project, configuration);
+
+ // add maven nature even for projects without valid pom.xml file
+ addMavenNature(project, monitor);
+ }
+
+ private void addMavenNature(IProject project, IProgressMonitor monitor) throws CoreException {
+ if (!project.hasNature(IMavenConstants.NATURE_ID)) {
+ IProjectDescription description = project.getDescription();
+ String[] prevNatures = description.getNatureIds();
+ String[] newNatures = new String[prevNatures.length + 1];
+ System.arraycopy(prevNatures, 0, newNatures, 1, prevNatures.length);
+ newNatures[0] = IMavenConstants.NATURE_ID;
+ description.setNatureIds(newNatures);
+ project.setDescription(description, monitor);
+ }
+ }
+
+ public void disableMavenNature(IProject project, IProgressMonitor monitor) throws CoreException {
+ monitor.subTask(Messages.ProjectConfigurationManager_task_disable_nature);
+
+ IMavenProjectFacade facade = projectManager.create(project, monitor);
+ if(facade!=null) {
+ ILifecycleMapping lifecycleMapping = getLifecycleMapping(facade, monitor);
+ ProjectConfigurationRequest request = new ProjectConfigurationRequest(facade, facade.getMavenProject(monitor), createMavenSession(facade, monitor), false /*updateSources*/);
+ lifecycleMapping.unconfigure(request, monitor);
+ }
+
+ project.deleteMarkers(IMavenConstants.MARKER_ID, true, IResource.DEPTH_INFINITE);
+
+ IProjectDescription description = project.getDescription();
+ ArrayList<String> newNatures = new ArrayList<String>();
+ for(String natureId : description.getNatureIds()) {
+ if(!IMavenConstants.NATURE_ID.equals(natureId)) {
+ newNatures.add(natureId);
+ }
+ }
+ description.setNatureIds(newNatures.toArray(new String[newNatures.size()]));
+ ArrayList<ICommand> newCommands = new ArrayList<ICommand>();
+ for (ICommand command : description.getBuildSpec()) {
+ if (!IMavenConstants.BUILDER_ID.equals(command.getBuilderName())) {
+ newCommands.add(command);
+ }
+ }
+ description.setBuildSpec(newCommands.toArray(new ICommand[newCommands.size()]));
+ project.setDescription(description, null);
+ }
+
+ // project creation
+
+ /**
+ * Creates simple Maven project
+ * <p>
+ * The following steps are executed in the given order:
+ * <ul>
+ * <li>Creates the workspace project</li>
+ * <li>Adds project to working set</li>
+ * <li>Creates the required folders</li>
+ * <li>Creates the POM</li>
+ * <li>Configures project</li>
+ * </ul>
+ * </p>
+ */
+ // XXX should use Maven plugin configurations instead of manually specifying folders
+ public void createSimpleProject(IProject project, IPath location, Model model, String[] directories,
+ ProjectImportConfiguration configuration, IProgressMonitor monitor) throws CoreException {
+ String projectName = project.getName();
+ monitor.beginTask(NLS.bind(Messages.ProjectConfigurationManager_task_creating, projectName), 5);
+
+ monitor.subTask(Messages.ProjectConfigurationManager_task_creating_workspace);
+ IProjectDescription description = ResourcesPlugin.getWorkspace().newProjectDescription(projectName);
+ description.setLocation(location);
+ project.create(description, monitor);
+ project.open(monitor);
+ monitor.worked(1);
+
+ addToWorkingSets(project, configuration.getWorkingSets());
+ monitor.worked(1);
+
+ monitor.subTask(Messages.ProjectConfigurationManager_task_creating_pom);
+ IFile pomFile = project.getFile(IMavenConstants.POM_FILE_NAME);
+ mavenModelManager.createMavenModel(pomFile, model);
+ monitor.worked(1);
+
+ monitor.subTask(Messages.ProjectConfigurationManager_task_creating_folders);
+ for(int i = 0; i < directories.length; i++ ) {
+ Util.createFolder(project.getFolder(directories[i]), false);
+ }
+ monitor.worked(1);
+
+ monitor.subTask(Messages.ProjectConfigurationManager_task_creating_project);
+ enableMavenNature(project, configuration.getResolverConfiguration(), monitor);
+ monitor.worked(1);
+ }
+
+ /**
+ * Creates project structure using Archetype and then imports created project
+ */
+ public void createArchetypeProject(IProject project, IPath location, Archetype archetype, String groupId,
+ String artifactId, String version, String javaPackage, Properties properties,
+ ProjectImportConfiguration configuration, IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask(NLS.bind(Messages.ProjectConfigurationManager_task_creating_project1, project.getName()), 2);
+
+ IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+
+ monitor.subTask(NLS.bind(Messages.ProjectConfigurationManager_task_executing_archetype, archetype.getGroupId(), archetype.getArtifactId()));
+ if(location == null) {
+ // if the project should be created in the workspace, figure out the path
+ location = workspaceRoot.getLocation();
+ }
+
+ try {
+
+
+
+ Artifact artifact = resolveArchetype(archetype, monitor);
+
+ ArchetypeGenerationRequest request = new ArchetypeGenerationRequest() //
+ .setTransferListener(maven.createTransferListener(monitor)) //
+ .setArchetypeGroupId(artifact.getGroupId()) //
+ .setArchetypeArtifactId(artifact.getArtifactId()) //
+ .setArchetypeVersion(artifact.getVersion()) //
+ .setArchetypeRepository(archetype.getRepository()) //
+ .setGroupId(groupId) //
+ .setArtifactId(artifactId) //
+ .setVersion(version) //
+ .setPackage(javaPackage) // the model does not have a package field
+ .setLocalRepository(maven.getLocalRepository()) //
+ .setRemoteArtifactRepositories(maven.getArtifactRepositories(true))
+ .setProperties(properties).setOutputDirectory(location.toPortableString());
+
+ MavenSession session = maven.createSession(maven.createExecutionRequest(monitor), null);
+
+ MavenSession oldSession = MavenPlugin.getDefault().setSession(session);
+
+ ArchetypeGenerationResult result;
+ try {
+ result = getArchetyper().generateProjectFromArchetype(request);
+ } finally {
+ MavenPlugin.getDefault().setSession(oldSession);
+ }
+
+ Exception cause = result.getCause();
+ if(cause != null) {
+ String msg = NLS.bind(Messages.ProjectConfigurationManager_error_unable_archetype, archetype.toString());
+ MavenLogger.log(msg, cause);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, msg, cause));
+ }
+ monitor.worked(1);
+
+ // XXX Archetyper don't allow to specify project folder
+ String projectFolder = location.append(artifactId).toFile().getAbsolutePath();
+
+ LocalProjectScanner scanner = new LocalProjectScanner(workspaceRoot.getLocation().toFile(), //
+ projectFolder, true, mavenModelManager, console);
+ scanner.run(monitor);
+
+ Set<MavenProjectInfo> projectSet = collectProjects(scanner.getProjects());
+
+ importProjects(projectSet, configuration, monitor);
+
+ monitor.worked(1);
+ } catch (CoreException e) {
+ throw e;
+ } catch (InterruptedException e) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ } catch (Exception ex) {
+ throw new CoreException(new Status(IStatus.ERROR, "org.eclipse.m2e", Messages.ProjectConfigurationManager_error_failed, ex)); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Apparently, Archetype#generateProjectFromArchetype 2.0-alpha-4 does not attempt to resolve archetype
+ * from configured remote repositories. To compensate, we populate local repo with archetype pom/jar.
+ */
+ private Artifact resolveArchetype(Archetype a, IProgressMonitor monitor) throws CoreException {
+ ArrayList<ArtifactRepository> repos = new ArrayList<ArtifactRepository>();
+ repos.addAll(maven.getArtifactRepositories()); // see org.apache.maven.archetype.downloader.DefaultDownloader#download
+
+ //MNGECLIPSE-1399 use archetype repository too, not just the default ones
+ String artifactRemoteRepository = a.getRepository();
+
+ try {
+
+ if (StringUtils.isBlank(artifactRemoteRepository)){
+
+ IMavenConfiguration mavenConfiguration = MavenPlugin.getDefault().getMavenConfiguration();
+ if (!mavenConfiguration.isOffline()){
+ //Try to find the repository from remote catalog if needed
+ final ArchetypeManager archetypeManager = MavenPlugin.getDefault().getArchetypeManager();
+ RemoteCatalogFactory factory = archetypeManager.findParentCatalogFactory(a, RemoteCatalogFactory.class);
+ if (factory != null) {
+ //Grab the computed remote repository url
+ artifactRemoteRepository = factory.getRepositoryUrl();
+ a.setRepository(artifactRemoteRepository);//Hopefully will prevent further lookups for the same archetype
+ }
+ }
+ }
+
+ if (StringUtils.isNotBlank(artifactRemoteRepository)) {
+ ArtifactRepository archetypeRepository = maven.createArtifactRepository("archetype", a.getRepository().trim()); //$NON-NLS-1$
+ repos.add(0,archetypeRepository);//If the archetype doesn't exist locally, this will be the first remote repo to be searched.
+ }
+
+ maven.resolve(a.getGroupId(), a.getArtifactId(),a.getVersion(), "pom", null, repos, monitor); //$NON-NLS-1$
+ return maven.resolve(a.getGroupId(), a.getArtifactId(),a.getVersion(), "jar", null, repos, monitor); //$NON-NLS-1$
+ } catch (CoreException e) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(Messages.ProjectConfigurationManager_error_resolve).append(a.getGroupId()).append(':').append(a.getArtifactId()).append(':').append(a.getVersion());
+ sb.append(Messages.ProjectConfigurationManager_error_resolve2);
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, sb.toString(), e));
+ }
+ }
+
+ private org.apache.maven.archetype.Archetype getArchetyper() {
+ return MavenPlugin.getDefault().getArchetype();
+ }
+
+ public Set<MavenProjectInfo> collectProjects(Collection<MavenProjectInfo> projects) {
+
+ // TODO what does this do?
+ return new LinkedHashSet<MavenProjectInfo>() {
+ private static final long serialVersionUID = 1L;
+
+ public Set<MavenProjectInfo> collectProjects(Collection<MavenProjectInfo> projects) {
+ for(MavenProjectInfo projectInfo : projects) {
+ console.logMessage("Collecting project info " + projectInfo);
+ add(projectInfo);
+ collectProjects(projectInfo.getProjects());
+ }
+ return this;
+ }
+ }.collectProjects(projects);
+ }
+
+ public ISchedulingRule getRule() {
+ return ResourcesPlugin.getWorkspace().getRuleFactory().buildRule();
+ }
+
+ private IProject create(MavenProjectInfo projectInfo, ProjectImportConfiguration configuration, IProgressMonitor monitor) throws CoreException {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IWorkspaceRoot root = workspace.getRoot();
+
+ File pomFile = projectInfo.getPomFile();
+ Model model = projectInfo.getModel();
+ if(model == null) {
+ model = maven.readModel(pomFile);
+ projectInfo.setModel(model);
+ }
+
+ String projectName = configuration.getProjectName(model);
+
+ File projectDir = pomFile.getParentFile();
+ String projectParent = projectDir.getParentFile().getAbsolutePath();
+
+ if (projectInfo.getBasedirRename() == MavenProjectInfo.RENAME_REQUIRED) {
+ File newProject = new File(projectDir.getParent(), projectName);
+ if(!projectDir.equals(newProject)) {
+ boolean renamed = projectDir.renameTo(newProject);
+ if(!renamed) {
+ StringBuilder msg = new StringBuilder();
+ msg.append(NLS.bind(Messages.ProjectConfigurationManager_error_rename, projectDir.getAbsolutePath())).append('.');
+ if (newProject.exists()) {
+ msg.append(NLS.bind(Messages.ProjectConfigurationManager_error_targetDir, newProject.getAbsolutePath()));
+ }
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, msg.toString(), null));
+ }
+ projectInfo.setPomFile(getCanonicalPomFile(newProject));
+ projectDir = newProject;
+ }
+ } else {
+ if(projectParent.equals(root.getLocation().toFile().getAbsolutePath())) {
+ // immediately under workspace root, project name must match filesystem directory name
+ projectName = projectDir.getName();
+ }
+ }
+
+ monitor.subTask(NLS.bind(Messages.ProjectConfigurationManager_task_importing2, projectName));
+
+ IProject project = root.getProject(projectName);
+ if(project.exists()) {
+ console.logError("Project " + projectName + " already exists");
+ return null;
+ }
+
+ if(projectDir.equals(root.getLocation().toFile())) {
+ console.logError("Can't create project " + projectName + " at Workspace folder");
+ return null;
+ }
+
+ if(projectParent.equals(root.getLocation().toFile().getAbsolutePath())) {
+ project.create(monitor);
+ } else {
+ IProjectDescription description = workspace.newProjectDescription(projectName);
+ description.setLocation(new Path(projectDir.getAbsolutePath()));
+ project.create(description, monitor);
+ }
+
+ if(!project.isOpen()) {
+ project.open(monitor);
+ }
+
+ ResolverConfiguration resolverConfiguration = configuration.getResolverConfiguration();
+ enableBasicMavenNature(project, resolverConfiguration, monitor);
+
+ return project;
+ }
+
+ private File getCanonicalPomFile(File projectDir) throws CoreException {
+ try {
+ return new File(projectDir.getCanonicalFile(), IMavenConstants.POM_FILE_NAME);
+ } catch(IOException ex) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, //
+ NLS.bind(Messages.ProjectConfigurationManager_0, projectDir.getAbsolutePath()), null));
+ }
+ }
+
+ public void mavenProjectChanged(MavenProjectChangedEvent[] events, IProgressMonitor monitor) {
+ for(MavenProjectChangedEvent event : events) {
+ try {
+ ILifecycleMapping lifecycleMapping = getLifecycleMapping(event.getMavenProject(), monitor);
+ if(lifecycleMapping != null) {
+ for(AbstractProjectConfigurator configurator : lifecycleMapping.getProjectConfigurators(event.getMavenProject(), monitor)) {
+ //MNGECLIPSE-2004 : only send the relevant event to the configurator
+ configurator.mavenProjectChanged(event, monitor);
+ }
+ }
+ } catch (CoreException e) {
+ MavenLogger.log(e);
+ }
+ }
+ }
+
+ public ILifecycleMapping getLifecycleMapping(IMavenProjectFacade projectFacade, IProgressMonitor monitor) throws CoreException {
+ if (projectFacade==null) {
+ return null;
+ }
+
+ return projectFacade.getLifecycleMapping(monitor);
+ }
+
+ public ILifecycleMapping getDefaultLifecycleMapping(IMavenProjectFacade projectFacade, IProgressMonitor monitor)
+ throws CoreException {
+ if(projectFacade == null) {
+ return null;
+ }
+
+ return projectFacade.getLifecycleMapping(monitor);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/WorkspaceStateWriter.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/WorkspaceStateWriter.java
new file mode 100644
index 00000000..a2f84921
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/WorkspaceStateWriter.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Properties;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+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.apache.maven.artifact.Artifact;
+
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.project.IMavenProjectChangedListener;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectChangedEvent;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+
+/**
+ * Maintains map file of maven artifacts present in workspace.
+ */
+public class WorkspaceStateWriter implements IMavenProjectChangedListener {
+
+ private MavenProjectManager projectManager;
+
+ public WorkspaceStateWriter(MavenProjectManager projectManager) {
+ this.projectManager = projectManager;
+ }
+
+ public void mavenProjectChanged(MavenProjectChangedEvent[] events, IProgressMonitor monitor) {
+ try {
+ Properties state = new Properties();
+
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ for(IMavenProjectFacade projectFacade : projectManager.getProjects()) {
+ try {
+ Artifact artifact = projectFacade.getMavenProject(monitor).getArtifact();
+ IFile pomFile = projectFacade.getPom();
+ IPath location = pomFile.getLocation();
+ if(location != null) {
+ File pom = location.toFile();
+ if(pom.canRead()) {
+ String key = artifact.getGroupId() + ":" + artifact.getArtifactId() + ":pom:" + artifact.getBaseVersion(); //$NON-NLS-1$ //$NON-NLS-2$
+ state.put(key, pom.getCanonicalPath());
+ }
+ }
+ IResource outputLocation = root.findMember(projectFacade.getOutputLocation());
+ if (!"pom".equals(artifact.getType()) && outputLocation != null && outputLocation.exists()) { //$NON-NLS-1$
+ String key = artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getType() + ":" + artifact.getBaseVersion(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ state.put(key, outputLocation.getLocation().toFile().getCanonicalPath());
+ }
+ } catch (CoreException ex) {
+ MavenLogger.log("Error writing workspace state file", ex);
+ }
+ }
+
+ OutputStream buf = new BufferedOutputStream(new FileOutputStream(projectManager.getWorkspaceStateFile()));
+ try {
+ state.store(buf, null);
+ } finally {
+ buf.close();
+ }
+
+ } catch(IOException ex) {
+ MavenLogger.log("Error writing workspace state file", ex);
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/AbstractMavenDependencyResolver.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/AbstractMavenDependencyResolver.java
new file mode 100644
index 00000000..819fd46a
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/AbstractMavenDependencyResolver.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.execution.MavenExecutionRequest;
+
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+
+/**
+ * AbstractMavenDependencyResolver
+ *
+ * @author igor
+ */
+public abstract class AbstractMavenDependencyResolver {
+
+ private ProjectRegistryManager manager;
+ private MutableProjectRegistry contextRegistry;
+
+ protected IMaven getMaven() {
+ return manager.getMaven();
+ }
+
+ final void setManager(ProjectRegistryManager manager) {
+ this.manager = manager;
+ }
+
+ protected ProjectRegistryManager getManager() {
+ return manager;
+ }
+
+ public abstract void resolveProjectDependencies(IMavenProjectFacade facade, MavenExecutionRequest mavenRequest, Set<Capability> capabilities, Set<RequiredCapability> requirements, IProgressMonitor monitor) throws CoreException;
+
+ void setContextProjectRegistry(MutableProjectRegistry contextRegistry) {
+ this.contextRegistry = contextRegistry;
+ }
+
+ protected List<MavenProjectFacade> getProjects() {
+ return Arrays.asList(contextRegistry.getProjects());
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/BasicProjectRegistry.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/BasicProjectRegistry.java
new file mode 100644
index 00000000..5ab82a63
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/BasicProjectRegistry.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+
+/**
+ * Registry of all workspace projects and their dependencies.
+ *
+ * @author igor
+ */
+abstract class BasicProjectRegistry implements Serializable {
+
+ private static final long serialVersionUID = 5542512601401896748L;
+
+ private final String m2e_version = MavenPlugin.getQualifiedVersion();
+
+ /**
+ * Map<ArtifactKey, IPath> Maps ArtifactKey to full workspace IPath of the POM file that defines this artifact.
+ */
+ protected final Map<ArtifactKey, IFile> workspaceArtifacts = new HashMap<ArtifactKey, IFile>();
+
+ /**
+ * Maps full pom IPath to MavenProjectFacade
+ */
+ protected final Map<IFile, MavenProjectFacade> workspacePoms = new HashMap<IFile, MavenProjectFacade>();
+
+ /**
+ * Maps required capabilities to projects that require them.
+ */
+ protected final Map<VersionlessKey, Map<RequiredCapability, Set<IFile>>> requiredCapabilities = new HashMap<VersionlessKey, Map<RequiredCapability, Set<IFile>>>();
+
+ /**
+ * Maps project pom.xml file to the capabilities provided by the project
+ */
+ protected final Map<IFile, Set<Capability>> projectCapabilities = new HashMap<IFile, Set<Capability>>();
+
+ /**
+ * Maps project pom.xml file to the capabilities required by the project
+ */
+ protected final Map<IFile, Set<RequiredCapability>> projectRequirements = new HashMap<IFile, Set<RequiredCapability>>();
+
+ protected BasicProjectRegistry() {
+ }
+
+ protected BasicProjectRegistry(BasicProjectRegistry other) {
+ replaceWith(other);
+ }
+
+ protected final void replaceWith(BasicProjectRegistry other) {
+ clear();
+
+ copy(other.workspaceArtifacts, workspaceArtifacts);
+ copy(other.workspacePoms, workspacePoms);
+ copy(other.projectCapabilities, projectCapabilities);
+ copy(other.projectRequirements, projectRequirements);
+ copy(other.requiredCapabilities, requiredCapabilities);
+ }
+
+ /**
+ * THIS IS NOT A GENERIC DEEP COPY IMPLEMENTATION!
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private static void copy(Map from, Map to) {
+ for(Map.Entry entry : (Set<Map.Entry>) from.entrySet()) {
+ Object value = entry.getValue();
+ if(value instanceof Map) {
+ Map map = new HashMap();
+ copy((Map) value, map);
+ value = map;
+ } else if(value instanceof Set) {
+ Set set = new HashSet((Set) value);
+ value = set;
+ }
+ to.put(entry.getKey(), value);
+ }
+ }
+
+ public MavenProjectFacade getProjectFacade(IFile pom) {
+ return workspacePoms.get(pom);
+ }
+
+ public MavenProjectFacade getProjectFacade(String groupId, String artifactId, String version) {
+ IFile path = workspaceArtifacts.get(new ArtifactKey(groupId, artifactId, version, null));
+ if(path == null) {
+ return null;
+ }
+ return workspacePoms.get(path);
+ }
+
+ /**
+ * @TODO return a List
+ */
+ public MavenProjectFacade[] getProjects() {
+ return workspacePoms.values().toArray(new MavenProjectFacade[workspacePoms.size()]);
+ }
+
+ public IFile getWorkspaceArtifact(ArtifactKey key) {
+ return workspaceArtifacts.get(key);
+ }
+
+ protected void clear() {
+ workspaceArtifacts.clear();
+ workspacePoms.clear();
+ requiredCapabilities.clear();
+ projectCapabilities.clear();
+ projectRequirements.clear();
+ }
+
+ public boolean isValid() {
+ return MavenPlugin.getQualifiedVersion().equals(m2e_version) //
+ && workspaceArtifacts != null //
+ && workspacePoms != null //
+ && requiredCapabilities != null //
+ && projectCapabilities != null //
+ && projectRequirements != null //
+ && areFacadesValid();
+ }
+
+ private boolean areFacadesValid() {
+ for(MavenProjectFacade facade : workspacePoms.values()) {
+ if(facade == null || facade.getPom() == null || facade.getPom().getLocation() == null) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected Set<RequiredCapability> getProjectRequirements(IFile pom) {
+ return projectRequirements.get(pom);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/Capability.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/Capability.java
new file mode 100644
index 00000000..6b7f767f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/Capability.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.io.Serializable;
+
+
+/**
+ * Capability
+ *
+ * @author igor
+ */
+public abstract class Capability implements Serializable {
+
+ private static final long serialVersionUID = 6057170997402911788L;
+
+ private final VersionlessKey versionlessKey;
+
+ public Capability(String namespace, String id) {
+ if(namespace == null || id == null) {
+ throw new NullPointerException();
+ }
+ this.versionlessKey = new VersionlessKey(namespace, id);
+ }
+
+ public VersionlessKey getVersionlessKey() {
+ return versionlessKey;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/DefaultMavenDependencyResolver.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/DefaultMavenDependencyResolver.java
new file mode 100644
index 00000000..c27b325b
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/DefaultMavenDependencyResolver.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.project.DependencyResolutionResult;
+import org.apache.maven.project.MavenProject;
+
+import org.sonatype.aether.graph.Dependency;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.project.IMavenMarkerManager;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+
+/**
+ * DefaultMavenDependencyResolver
+ *
+ * @author igor
+ */
+public class DefaultMavenDependencyResolver extends AbstractMavenDependencyResolver {
+ private final IMavenMarkerManager markerManager;
+
+ public DefaultMavenDependencyResolver(ProjectRegistryManager manager, IMavenMarkerManager markerManager) {
+ setManager(manager);
+ this.markerManager = markerManager;
+ }
+
+ public void resolveProjectDependencies(IMavenProjectFacade facade, MavenExecutionRequest mavenRequest,
+ Set<Capability> capabilities, Set<RequiredCapability> requirements, IProgressMonitor monitor)
+ throws CoreException {
+ markerManager.deleteMarkers(facade.getPom(), IMavenConstants.MARKER_DEPENDENCY_ID);
+
+ MavenExecutionResult mavenResult = getMaven().readProject(mavenRequest, monitor);
+
+ markerManager.addMarkers(facade.getPom(), IMavenConstants.MARKER_DEPENDENCY_ID, mavenResult);
+
+ if(!facade.getResolverConfiguration().shouldResolveWorkspaceProjects()) {
+ return;
+ }
+
+ MavenProject mavenProject = facade.getMavenProject();
+
+ // dependencies
+
+ // parent
+ Artifact parentArtifact = mavenProject.getParentArtifact();
+ if(parentArtifact != null) {
+ requirements.add(MavenRequiredCapability.createMavenParent(new ArtifactKey(parentArtifact)));
+ }
+
+ // resolved dependencies
+ for(Artifact artifact : mavenProject.getArtifacts()) {
+ requirements.add(MavenRequiredCapability.createMaven(new ArtifactKey(artifact), artifact.getScope(),
+ artifact.isOptional()));
+ }
+
+ // extension plugins (affect packaging type calculation)
+ for(Plugin plugin : mavenProject.getBuildPlugins()) {
+ if(plugin.isExtensions()) {
+ ArtifactKey artifactKey = new ArtifactKey(plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion(),
+ null);
+ requirements.add(MavenRequiredCapability.createMaven(artifactKey, "plugin", false)); //$NON-NLS-1$
+ }
+ }
+
+ // missing dependencies
+ DependencyResolutionResult resolutionResult = mavenResult.getDependencyResolutionResult();
+ if(resolutionResult != null && resolutionResult.getUnresolvedDependencies() != null) {
+ for(Dependency dependency : resolutionResult.getUnresolvedDependencies()) {
+ org.sonatype.aether.artifact.Artifact artifact = dependency.getArtifact();
+ ArtifactKey dependencyKey = new ArtifactKey(artifact.getGroupId(), artifact.getArtifactId(),
+ artifact.getVersion(), null);
+ requirements.add(MavenRequiredCapability.createMaven(dependencyKey, dependency.getScope(),
+ dependency.isOptional()));
+ }
+ }
+
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipsePluginDependenciesResolver.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipsePluginDependenciesResolver.java
new file mode 100644
index 00000000..db507922
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipsePluginDependenciesResolver.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.util.List;
+
+import org.codehaus.plexus.component.annotations.Component;
+
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.PluginResolutionException;
+import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
+import org.apache.maven.plugin.internal.PluginDependenciesResolver;
+
+import org.sonatype.aether.RepositorySystemSession;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.graph.DependencyFilter;
+import org.sonatype.aether.graph.DependencyNode;
+import org.sonatype.aether.repository.RemoteRepository;
+
+
+@Component(role = PluginDependenciesResolver.class)
+public class EclipsePluginDependenciesResolver extends DefaultPluginDependenciesResolver {
+
+ /*
+ * Plugin realms are cached and there is currently no way to purge cached
+ * realms due to http://jira.codehaus.org/browse/MNG-4194.
+ *
+ * Workspace plugins cannot be cached, so we disable this until MNG-4194 is fixed.
+ *
+ * Corresponding m2e JIRA https://issues.sonatype.org/browse/MNGECLIPSE-1448
+ */
+
+ @Override
+ public Artifact resolve(Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session)
+ throws PluginResolutionException {
+ boolean disabled = EclipseWorkspaceArtifactRepository.isDisabled();
+ EclipseWorkspaceArtifactRepository.setDisabled(true);
+ try {
+ return super.resolve(plugin, repositories, session);
+ } finally {
+ EclipseWorkspaceArtifactRepository.setDisabled(disabled);
+ }
+ }
+
+ @Override
+ public DependencyNode resolve(Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
+ List<RemoteRepository> repositories, RepositorySystemSession session) throws PluginResolutionException {
+ boolean disabled = EclipseWorkspaceArtifactRepository.isDisabled();
+ EclipseWorkspaceArtifactRepository.setDisabled(true);
+ try {
+ return super.resolve(plugin, pluginArtifact, dependencyFilter, repositories, session);
+ } finally {
+ EclipseWorkspaceArtifactRepository.setDisabled(disabled);
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipseWorkspaceArtifactRepository.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipseWorkspaceArtifactRepository.java
new file mode 100644
index 00000000..c38a1c89
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/EclipseWorkspaceArtifactRepository.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+
+import org.apache.maven.repository.LocalArtifactRepository;
+
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.repository.WorkspaceReader;
+import org.sonatype.aether.repository.WorkspaceRepository;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+
+public final class EclipseWorkspaceArtifactRepository extends LocalArtifactRepository implements WorkspaceReader {
+
+ private static final long serialVersionUID = 1018465082844566543L;
+
+ private final transient ProjectRegistryManager.Context context;
+
+ private static final ThreadLocal<Boolean> disabled = new ThreadLocal<Boolean>();
+
+ private WorkspaceRepository workspaceRepository;
+
+ public EclipseWorkspaceArtifactRepository(ProjectRegistryManager.Context context) {
+ this.context = context;
+ this.workspaceRepository = new WorkspaceRepository("ide", getClass()); //$NON-NLS-1$
+ }
+
+ protected File resolveAsEclipseProject(String groupId, String artifactId, String baseVersion, String classifier, String extension) {
+ if (isDisabled()) {
+ return null;
+ }
+
+ if(context == null) { // XXX this is actually a bug
+ return null;
+ }
+
+ // check in the workspace, note that workspace artifacts never have classifiers
+ ArtifactKey key = new ArtifactKey(groupId, artifactId, baseVersion, null);
+ IFile pom = context.state.getWorkspaceArtifact(key);
+ if(pom == null || !pom.isAccessible()) {
+ return null;
+ }
+ if(context.pom != null && pom.equals(context.pom)) {
+ return null;
+ }
+
+// if(!"pom".equals(artifact.getType())) {
+// return false;
+// }
+
+ if(context.resolverConfiguration.shouldResolveWorkspaceProjects()) {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IPath file = pom.getLocation();
+ if (!"pom".equals(extension)) { //$NON-NLS-1$
+ MavenProjectFacade facade = context.state.getProjectFacade(pom);
+ IFolder outputLocation = root.getFolder(facade.getOutputLocation());
+ if (outputLocation.exists()) {
+ file = outputLocation.getLocation();
+ }
+ }
+
+ return file.toFile();
+ }
+
+ return null;
+ }
+
+ public File findArtifact(Artifact artifact) {
+ return resolveAsEclipseProject(artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(),
+ artifact.getClassifier(), artifact.getExtension());
+ }
+
+ public org.apache.maven.artifact.Artifact find(org.apache.maven.artifact.Artifact artifact) {
+ File file = resolveAsEclipseProject(artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(),
+ artifact.getClassifier(), artifact.getType());
+
+ if(file != null) {
+ artifact.setFile(file);
+ artifact.setResolved(true);
+ }
+
+ return artifact;
+ }
+
+ public boolean hasLocalMetadata() {
+ return false; // XXX
+ }
+
+ public static void setDisabled(boolean disable) {
+ disabled.set(disable? Boolean.TRUE: null);
+ }
+
+ public static boolean isDisabled() {
+ return Boolean.TRUE.equals(disabled.get());
+ }
+
+ public int hashCode() {
+ return 0; // no state
+ }
+
+ public boolean equals(Object obj) {
+ return obj instanceof EclipseWorkspaceArtifactRepository;
+ }
+
+ public List<String> findVersions(Artifact artifact) {
+ return findVersions(artifact.getGroupId(), artifact.getArtifactId());
+ }
+
+ @Override
+ public List<String> findVersions(org.apache.maven.artifact.Artifact artifact) {
+ return findVersions(artifact.getGroupId(), artifact.getArtifactId());
+ }
+
+ private List<String> findVersions(String groupId, String artifactId) {
+ ArrayList<String> versions = new ArrayList<String>();
+
+ if (isDisabled()) {
+ return versions;
+ }
+
+ if(context == null) { // XXX this is actually a bug
+ return versions;
+ }
+
+ for (MavenProjectFacade facade : context.state.getProjects()) {
+ ArtifactKey artifactKey = facade.getArtifactKey();
+ if (groupId.equals(artifactKey.getGroupId()) && artifactId.equals(artifactKey.getArtifactId())) {
+ versions.add(artifactKey.getVersion());
+ }
+ }
+
+ return versions;
+ }
+
+ public WorkspaceRepository getRepository() {
+ return workspaceRepository;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ILifecycleMapping2.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ILifecycleMapping2.java
new file mode 100644
index 00000000..2b3d1960
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ILifecycleMapping2.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+
+/**
+ * ILifecycleMapping2
+ *
+ * @author igor
+ */
+public interface ILifecycleMapping2 extends ILifecycleMapping {
+ public AbstractMavenDependencyResolver getDependencyResolver(IProgressMonitor monitor);
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/IProjectRegistry.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/IProjectRegistry.java
new file mode 100644
index 00000000..dc4c605d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/IProjectRegistry.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import org.eclipse.core.resources.IFile;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+
+/**
+ * Registry of all known workspace maven projects.
+ *
+ * @author igor
+ */
+public interface IProjectRegistry {
+
+ public MavenProjectFacade getProjectFacade(IFile pom);
+
+ public MavenProjectFacade getProjectFacade(String groupId, String artifactId, String version);
+
+ public MavenProjectFacade[] getProjects();
+
+ public IFile getWorkspaceArtifact(ArtifactKey key);
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenCapability.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenCapability.java
new file mode 100644
index 00000000..445fb35e
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenCapability.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+
+/**
+ * MavenCapability
+ *
+ * @author igor
+ */
+public class MavenCapability extends Capability {
+
+ private static final long serialVersionUID = 8930981127331238566L;
+
+ /**
+ * Regular Maven dependency as defined in <dependency/> pom.xml element.
+ */
+ public static final String NS_MAVEN_ARTIFACT = "maven-artifact"; //$NON-NLS-1$
+
+ /**
+ * Maven parent dependency as defined in <parent/> pom.xml element.
+ */
+ public static final String NS_MAVEN_PARENT = "maven-parent"; //$NON-NLS-1$
+
+ private final String version;
+
+ private MavenCapability(String namespace, String id, String version) {
+ super(namespace, id);
+ this.version = version;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public String toString() {
+ return getVersionlessKey().toString() + "/" + version; //$NON-NLS-1$
+ }
+
+ public int hashCode() {
+ int hash = getVersionlessKey().hashCode();
+ hash = hash * 17 + version.hashCode();
+ return hash;
+ }
+
+ public boolean equals(Object obj) {
+ if(this == obj) {
+ return true;
+ }
+ if(!(obj instanceof MavenCapability)) {
+ return false;
+ }
+ MavenCapability other = (MavenCapability) obj;
+ return getVersionlessKey().equals(other.getVersionlessKey()) && version.equals(other.version);
+ }
+
+ public static MavenCapability createMaven(ArtifactKey key) {
+ return new MavenCapability(NS_MAVEN_ARTIFACT, getId(key), key.getVersion());
+ }
+
+ public static MavenCapability createMavenParent(ArtifactKey key) {
+ return new MavenCapability(NS_MAVEN_PARENT, getId(key), key.getVersion());
+ }
+
+ static String getId(ArtifactKey key) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(key.getGroupId());
+ sb.append(':').append(key.getArtifactId());
+ if(key.getClassifier() != null) {
+ sb.append(':').append(key.getClassifier());
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenProjectFacade.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenProjectFacade.java
new file mode 100644
index 00000000..28dbf8f3
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenProjectFacade.java
@@ -0,0 +1,382 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+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.Status;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.ArtifactRef;
+import org.eclipse.m2e.core.embedder.ArtifactRepositoryRef;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.IMavenProjectVisitor;
+import org.eclipse.m2e.core.project.IMavenProjectVisitor2;
+import org.eclipse.m2e.core.project.MavenProjectUtils;
+import org.eclipse.m2e.core.project.MavenUpdateRequest;
+import org.eclipse.m2e.core.project.ResolverConfiguration;
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+
+
+/**
+ * MavenProject facade
+ */
+public class MavenProjectFacade implements IMavenProjectFacade, Serializable {
+
+ private static final long serialVersionUID = 707484407691175077L;
+
+ private final ProjectRegistryManager manager;
+
+ private final IFile pom;
+
+ private final File pomFile;
+
+ private transient MavenProject mavenProject;
+ private transient MavenExecutionPlan executionPlan;
+
+ private transient Map<String, Object> sessionProperties;
+
+ private boolean hasValidConfiguration = false;
+
+ // XXX make final, there should be no need to change it
+ private ResolverConfiguration resolverConfiguration;
+
+ private final long[] timestamp = new long[ProjectRegistryManager.METADATA_PATH.size() + 1];
+
+ // cached values from mavenProject
+ private ArtifactKey artifactKey;
+ private List<String> modules;
+ private String packaging;
+ private IPath[] resourceLocations;
+ private IPath[] testResourceLocations;
+ private IPath[] compileSourceLocations;
+ private IPath[] testCompileSourceLocations;
+ private IPath outputLocation;
+ private IPath testOutputLocation;
+ private Set<ArtifactRef> artifacts;
+ private Set<ArtifactRepositoryRef> artifactRepositories;
+ private Set<ArtifactRepositoryRef> pluginArtifactRepositories;
+
+ private transient ILifecycleMapping lifecycleMapping;
+
+ public MavenProjectFacade(ProjectRegistryManager manager, IFile pom, MavenProject mavenProject,
+ ResolverConfiguration resolverConfiguration, ILifecycleMapping lifecycleMapping) {
+ this.manager = manager;
+ this.pom = pom;
+ IPath location = pom.getLocation();
+ this.pomFile = location == null ? null : location.toFile(); // save pom file
+ this.resolverConfiguration = resolverConfiguration;
+ setMavenProject(mavenProject);
+ updateTimestamp();
+ }
+
+ private void setMavenProject(MavenProject mavenProject) {
+ this.mavenProject = mavenProject;
+
+ this.artifactKey = new ArtifactKey(mavenProject.getArtifact());
+ this.packaging = mavenProject.getPackaging();
+ this.modules = mavenProject.getModules();
+
+ this.resourceLocations = MavenProjectUtils.getResourceLocations(getProject(), mavenProject.getResources());
+ this.testResourceLocations = MavenProjectUtils.getResourceLocations(getProject(), mavenProject.getTestResources());
+ this.compileSourceLocations = MavenProjectUtils.getSourceLocations(getProject(), mavenProject.getCompileSourceRoots());
+ this.testCompileSourceLocations = MavenProjectUtils.getSourceLocations(getProject(),mavenProject.getTestCompileSourceRoots());
+
+ IPath fullPath = getProject().getFullPath();
+
+ IPath path = getProjectRelativePath(mavenProject.getBuild().getOutputDirectory());
+ this.outputLocation = (path != null) ? fullPath.append(path) : null;
+
+ path = getProjectRelativePath(mavenProject.getBuild().getTestOutputDirectory());
+ this.testOutputLocation = path != null ? fullPath.append(path) : null;
+
+ setMavenProjectArtifacts();
+
+ this.artifactRepositories = new LinkedHashSet<ArtifactRepositoryRef>();
+ for(ArtifactRepository repository : mavenProject.getRemoteArtifactRepositories()) {
+ this.artifactRepositories.add(new ArtifactRepositoryRef(repository));
+ }
+
+ this.pluginArtifactRepositories = new LinkedHashSet<ArtifactRepositoryRef>();
+ for(ArtifactRepository repository : mavenProject.getPluginArtifactRepositories()) {
+ this.pluginArtifactRepositories.add(new ArtifactRepositoryRef(repository));
+ }
+ }
+
+ public void setMavenProject() {
+ setMavenProject(mavenProject);
+ }
+
+ /**
+ * Returns project relative paths of resource directories
+ */
+ public IPath[] getResourceLocations() {
+ return resourceLocations;
+ }
+
+ /**
+ * Returns project relative paths of test resource directories
+ */
+ public IPath[] getTestResourceLocations() {
+ return testResourceLocations;
+ }
+
+ public IPath[] getCompileSourceLocations() {
+ return compileSourceLocations;
+ }
+
+ public IPath[] getTestCompileSourceLocations() {
+ return testCompileSourceLocations;
+ }
+
+ /**
+ * Returns project resource for given file system location or null the location is outside of project.
+ *
+ * @param resourceLocation absolute file system location
+ * @return IPath the full, absolute workspace path resourceLocation
+ */
+ public IPath getProjectRelativePath(String resourceLocation) {
+ return MavenProjectUtils.getProjectRelativePath(getProject(), resourceLocation);
+ }
+
+ /**
+ * Returns the full, absolute path of this project maven build output directory relative to the workspace or null if
+ * maven build output directory cannot be determined or outside of the workspace.
+ */
+ public IPath getOutputLocation() {
+ return outputLocation;
+ }
+
+ /**
+ * Returns the full, absolute path of this project maven build test output directory relative to the workspace or null
+ * if maven build output directory cannot be determined or outside of the workspace.
+ */
+ public IPath getTestOutputLocation() {
+ return testOutputLocation;
+ }
+
+ public IPath getFullPath() {
+ return getProject().getFullPath();
+ }
+
+ /**
+ * Lazy load and cache MavenProject instance
+ */
+ public synchronized MavenProject getMavenProject(IProgressMonitor monitor) throws CoreException {
+ if (mavenProject == null) {
+ //this used to just pass in 'true' for 'offline'. when the local repo was removed or
+ //corrupted, though, the project wouldn't load correctly
+ IMavenConfiguration mavenConfiguration = MavenPlugin.getDefault().getMavenConfiguration();
+ boolean isOffline = mavenConfiguration.isOffline();
+ MavenExecutionResult result = manager.readProjectWithDependencies(pom, resolverConfiguration, //
+ new MavenUpdateRequest(isOffline, false /* updateSnapshots */), monitor);
+ mavenProject = result.getProject();
+ if (mavenProject == null) {
+ MultiStatus status = new MultiStatus(IMavenConstants.PLUGIN_ID, 0, Messages.MavenProjectFacade_error, null);
+ List<Throwable> exceptions = result.getExceptions();
+ for (Throwable e : exceptions) {
+ status.add(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, 0, e.getMessage(), e));
+ }
+ throw new CoreException(status);
+ }
+ }
+ return mavenProject;
+ }
+
+ public synchronized MavenExecutionPlan getExecutionPlan(IProgressMonitor monitor) throws CoreException {
+ if (executionPlan == null) {
+ executionPlan = manager.calculateExecutionPlan(this, monitor);
+ }
+ return executionPlan;
+ }
+
+ public String getPackaging() {
+ return packaging;
+ }
+
+ public IProject getProject() {
+ return pom.getProject();
+ }
+
+ public IFile getPom() {
+ return pom;
+ }
+
+ public File getPomFile() {
+ return pomFile;
+ }
+
+ /**
+ * Returns the full, absolute path of the given file relative to the workspace. Returns null if the file does not
+ * exist or is not a member of this project.
+ */
+ public IPath getFullPath(File file) {
+ return MavenProjectUtils.getFullPath(getProject(), file);
+ }
+
+ /**
+ * Visits trough Maven project artifacts and modules
+ *
+ * @param visitor a project visitor used to visit Maven project
+ * @param flags flags to specify visiting behavior. See {@link IMavenProjectVisitor#LOAD},
+ * {@link IMavenProjectVisitor#NESTED_MODULES}.
+ */
+ public void accept(IMavenProjectVisitor visitor, int flags) throws CoreException {
+ acceptImpl(visitor, flags, null);
+ }
+
+ public void accept(IMavenProjectVisitor2 visitor, int flags, IProgressMonitor monitor) throws CoreException {
+ acceptImpl(visitor, flags, monitor);
+ }
+
+ private void acceptImpl(IMavenProjectVisitor visitor, int flags, IProgressMonitor monitor) throws CoreException {
+ if(visitor.visit(this)) {
+ if (visitor instanceof IMavenProjectVisitor2 && monitor != null) {
+ MavenProject mavenProject = ((flags & IMavenProjectVisitor.LOAD) > 0)? getMavenProject(monitor): getMavenProject();
+ if (mavenProject != null) {
+ for(Artifact artifact : mavenProject.getArtifacts()) {
+ ((IMavenProjectVisitor2) visitor).visit(this, artifact);
+ }
+ }
+ }
+ }
+ }
+
+ public List<String> getMavenProjectModules() {
+ return modules;
+ }
+
+ public Set<ArtifactRef> getMavenProjectArtifacts() {
+ return artifacts;
+ }
+
+ void setMavenProjectArtifacts() {
+ this.artifacts = ArtifactRef.fromArtifact(mavenProject.getArtifacts());
+ }
+
+ public ResolverConfiguration getResolverConfiguration() {
+ return resolverConfiguration;
+ }
+
+ public void setResolverConfiguration(ResolverConfiguration configuration) {
+ resolverConfiguration = configuration;
+ }
+
+ /**
+ * @return true if maven project needs to be re-read from disk
+ */
+ public boolean isStale() {
+ IProject project = getProject();
+ int i = 0;
+ for(IPath path : ProjectRegistryManager.METADATA_PATH) {
+ if (timestamp[i] != getModificationStamp(project.getFile(path))) {
+ return true;
+ }
+ i++;
+ }
+ return timestamp[timestamp.length - 1] != getModificationStamp(pom);
+ }
+
+ private void updateTimestamp() {
+ IProject project = getProject();
+ int i = 0;
+ for(IPath path : ProjectRegistryManager.METADATA_PATH) {
+ timestamp[i] = getModificationStamp(project.getFile(path));
+ i++;
+ }
+ timestamp[timestamp.length - 1] = getModificationStamp(pom);
+ }
+
+ private static long getModificationStamp(IFile file) {
+ /*
+ * this implementation misses update in the following scenario
+ *
+ * 1. two files, A and B, with different content were created with same localTimeStamp
+ * 2. original A was deleted and B moved to A
+ *
+ * See also https://bugs.eclipse.org/bugs/show_bug.cgi?id=160728
+ */
+ return file.getLocalTimeStamp() + file.getModificationStamp();
+ }
+
+ public ArtifactKey getArtifactKey() {
+ return artifactKey;
+ }
+
+ public MavenProject getMavenProject() {
+ return mavenProject;
+ }
+
+ public synchronized void setSessionProperty(String key, Object value) {
+ if (sessionProperties == null) {
+ sessionProperties = new HashMap<String, Object>();
+ }
+ if (value != null) {
+ sessionProperties.put(key, value);
+ } else {
+ sessionProperties.remove(key);
+ }
+ }
+
+ public synchronized Object getSessionProperty(String key) {
+ return sessionProperties != null? sessionProperties.get(key): null;
+ }
+
+ public Set<ArtifactRepositoryRef> getArtifactRepositoryRefs() {
+ return artifactRepositories;
+ }
+
+ public Set<ArtifactRepositoryRef> getPluginArtifactRepositoryRefs() {
+ return pluginArtifactRepositories;
+ }
+
+ public ILifecycleMapping getLifecycleMapping(IProgressMonitor monitor) throws CoreException {
+ if ( lifecycleMapping == null ) {
+ lifecycleMapping = manager.getLifecycleMapping(pom, getMavenProject(monitor), getResolverConfiguration(), monitor);
+ }
+ return lifecycleMapping;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.core.project.IMavenProjectFacade#hasValidConfiguration()
+ */
+ public boolean hasValidConfiguration() {
+ return hasValidConfiguration;
+ }
+
+ public void setHasValidConfiguration(boolean hasValidConfiguration) {
+ this.hasValidConfiguration = hasValidConfiguration;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenRequiredCapability.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenRequiredCapability.java
new file mode 100644
index 00000000..1f0c3dbe
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenRequiredCapability.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.artifact.versioning.VersionRange;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+
+public class MavenRequiredCapability extends RequiredCapability {
+
+ private static final long serialVersionUID = 3254716937353332553L;
+
+ private final String versionRange;
+
+ private final String scope;
+
+ private final boolean optional;
+
+ private MavenRequiredCapability(String namespace, String id, String versionRange, String scope, boolean optional) {
+ super(namespace, id);
+
+ if(versionRange == null) {
+ throw new NullPointerException();
+ }
+
+ this.versionRange = versionRange;
+ this.scope = scope;
+ this.optional = optional;
+ }
+
+ public static MavenRequiredCapability createMaven(ArtifactKey key, String scope, boolean optional) {
+ return new MavenRequiredCapability(MavenCapability.NS_MAVEN_ARTIFACT, MavenCapability.getId(key), key.getVersion(),
+ scope, optional);
+ }
+
+ public static MavenRequiredCapability createMavenParent(ArtifactKey key) {
+ return new MavenRequiredCapability(MavenCapability.NS_MAVEN_PARENT, MavenCapability.getId(key), key.getVersion(),
+ null, false);
+ }
+
+ public boolean isPotentialMatch(Capability capability) {
+ if(capability instanceof MavenCapability && getVersionlessKey().equals(capability.getVersionlessKey())) {
+ try {
+ // TODO may need to cache parsed version and versionRange for performance reasons
+ ArtifactVersion version = new DefaultArtifactVersion(((MavenCapability) capability).getVersion());
+ VersionRange range = VersionRange.createFromVersionSpec(versionRange);
+ return range.containsVersion(version);
+ } catch(InvalidVersionSpecificationException ex) {
+ return true; // better safe than sorry
+ }
+ }
+ return false;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getVersionlessKey().toString());
+ if(scope != null) {
+ sb.append(':').append(scope);
+ }
+ sb.append('/').append(versionRange);
+ if(optional) {
+ sb.append("(optional)"); //$NON-NLS-1$
+ }
+ return sb.toString();
+ }
+
+ public int hashCode() {
+ int hash = getVersionlessKey().hashCode();
+ hash = hash * 17 + versionRange.hashCode();
+ hash = hash * 17 + (scope != null ? scope.hashCode() : 0);
+ hash = hash * 17 + (optional ? 1 : 0);
+ return hash;
+ }
+
+ public boolean equals(Object obj) {
+ if(this == obj) {
+ return true;
+ }
+ if(!(obj instanceof MavenRequiredCapability)) {
+ return false;
+ }
+ MavenRequiredCapability other = (MavenRequiredCapability) obj;
+ return getVersionlessKey().equals(other.getVersionlessKey()) && versionRange.equals(other.versionRange)
+ && eq(scope, other.scope) && optional == other.optional;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MutableProjectRegistry.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MutableProjectRegistry.java
new file mode 100644
index 00000000..a2526c98
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MutableProjectRegistry.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+
+/**
+ * WorkspaceStateDelta
+ *
+ * @author igor
+ */
+public class MutableProjectRegistry extends BasicProjectRegistry implements IProjectRegistry {
+
+ private static final long serialVersionUID = -4106047696261024741L;
+
+ private final ProjectRegistry parent;
+
+ private final int parentVersion;
+
+ private boolean closed;
+
+ public MutableProjectRegistry(ProjectRegistry state) {
+ super(state);
+ this.parent = state;
+ this.parentVersion = state.getVersion();
+ }
+
+ private void assertNotClosed() {
+ if(closed) {
+ throw new IllegalStateException("Can't modify closed MutableProjectRegistry"); //$NON-NLS-1$
+ }
+ }
+
+ public void setProject(IFile pom, MavenProjectFacade facade) {
+ assertNotClosed();
+
+ // remove
+ MavenProjectFacade oldFacade = workspacePoms.remove(pom);
+ if(oldFacade != null) {
+ workspaceArtifacts.remove(oldFacade.getArtifactKey());
+ }
+ if(facade != null) {
+ // Add the project to workspaceProjects map
+ workspacePoms.put(pom, facade);
+
+ // Add the project to workspaceArtifacts map
+ workspaceArtifacts.put(facade.getArtifactKey(), pom);
+ }
+ }
+
+ public void removeProject(IFile pom, ArtifactKey mavenProject) {
+ assertNotClosed();
+
+ // remove project from requiredCapabilities map
+ removeRequiredCapabilities(pom);
+
+ // Remove the project from workspaceProjects, projectRequirements and projectCapabilities maps
+ workspacePoms.remove(pom);
+ projectRequirements.remove(pom);
+ projectCapabilities.remove(pom);
+
+ // Remove the project from workspaceArtifacts map
+ if(mavenProject != null) {
+ workspaceArtifacts.remove(mavenProject);
+ }
+ }
+
+ static boolean isSameProject(IResource r1, IResource r2) {
+ if(r1 == null || r2 == null) {
+ return false;
+ }
+ return r1.getProject().equals(r2.getProject());
+ }
+
+ public Set<IFile> removeWorkspaceModules(IFile pom, ArtifactKey mavenProject) {
+ assertNotClosed();
+
+ return getDependents(MavenCapability.createMavenParent(mavenProject), true);
+ }
+
+ public boolean isStale() {
+ return parentVersion != parent.getVersion();
+ }
+
+ public void close() {
+ this.closed = true;
+
+ clear();
+ }
+
+ private boolean isClosed() {
+ return closed;
+ }
+
+ // IProjectRegistry
+
+ public MavenProjectFacade getProjectFacade(IFile pom) {
+ if(isClosed()) {
+ return parent.getProjectFacade(pom);
+ }
+ return super.getProjectFacade(pom);
+ }
+
+ public MavenProjectFacade getProjectFacade(String groupId, String artifactId, String version) {
+ if(isClosed()) {
+ return parent.getProjectFacade(groupId, artifactId, version);
+ }
+ return super.getProjectFacade(groupId, artifactId, version);
+ }
+
+ public MavenProjectFacade[] getProjects() {
+ if(isClosed()) {
+ return parent.getProjects();
+ }
+ return super.getProjects();
+ }
+
+ public IFile getWorkspaceArtifact(ArtifactKey key) {
+ if(isClosed()) {
+ return parent.getWorkspaceArtifact(key);
+ }
+ return super.getWorkspaceArtifact(key);
+ }
+
+ // low level access and manipulation
+
+ /**
+ * Returns all workspace projects that require given Capability.
+ */
+ public Set<IFile> getDependents(Capability capability, boolean remove) {
+ Map<RequiredCapability, Set<IFile>> rs = requiredCapabilities.get(capability.getVersionlessKey());
+ if(rs == null) {
+ return Collections.emptySet();
+ }
+ Set<IFile> result = new LinkedHashSet<IFile>();
+ Iterator<Entry<RequiredCapability, Set<IFile>>> iter = rs.entrySet().iterator();
+ while(iter.hasNext()) {
+ Entry<RequiredCapability, Set<IFile>> entry = iter.next();
+ if(entry.getKey().isPotentialMatch(capability)) {
+ result.addAll(entry.getValue());
+ if(remove) {
+ iter.remove();
+ }
+ }
+ }
+ if(remove && rs.isEmpty()) {
+ requiredCapabilities.remove(capability.getVersionlessKey());
+ }
+ return result;
+ }
+
+ /**
+ * Returns all workspace projects that require given versionless Capability.
+ */
+ public Set<IFile> getDependents(VersionlessKey capability, boolean remove) {
+ Map<RequiredCapability, Set<IFile>> rs;
+ if(remove) {
+ rs = requiredCapabilities.remove(capability);
+ } else {
+ rs = requiredCapabilities.get(capability);
+ }
+ if(rs == null) {
+ return Collections.emptySet();
+ }
+ Set<IFile> result = new LinkedHashSet<IFile>();
+ for(Set<IFile> dependents : rs.values()) {
+ result.addAll(dependents);
+ }
+ return result;
+ }
+
+ private void addRequiredCapability(IFile pom, RequiredCapability req) {
+ Map<RequiredCapability, Set<IFile>> keyEntry = requiredCapabilities.get(req.getVersionlessKey());
+ if(keyEntry == null) {
+ keyEntry = new HashMap<RequiredCapability, Set<IFile>>();
+ requiredCapabilities.put(req.getVersionlessKey(), keyEntry);
+ }
+ Set<IFile> poms = keyEntry.get(req);
+ if(poms == null) {
+ poms = new HashSet<IFile>();
+ keyEntry.put(req, poms);
+ }
+ poms.add(pom);
+ }
+
+ public Set<Capability> setCapabilities(IFile pom, Set<Capability> capabilities) {
+ return capabilities != null ? projectCapabilities.put(pom, capabilities) : projectCapabilities.remove(pom);
+ }
+
+ public Set<RequiredCapability> setRequirements(IFile pom, Set<RequiredCapability> requirements) {
+ removeRequiredCapabilities(pom);
+ if(requirements != null) {
+ for(RequiredCapability requirement : requirements) {
+ addRequiredCapability(pom, requirement);
+ }
+ return projectRequirements.put(pom, requirements);
+ }
+ return projectRequirements.remove(pom);
+ }
+
+ private void removeRequiredCapabilities(IFile pom) {
+ // TODO likely too slow
+ Iterator<Entry<VersionlessKey, Map<RequiredCapability, Set<IFile>>>> keysIter = requiredCapabilities.entrySet()
+ .iterator();
+ while(keysIter.hasNext()) {
+ Entry<VersionlessKey, Map<RequiredCapability, Set<IFile>>> keysEntry = keysIter.next();
+ Iterator<Entry<RequiredCapability, Set<IFile>>> requirementsIter = keysEntry.getValue().entrySet().iterator();
+ while(requirementsIter.hasNext()) {
+ Entry<RequiredCapability, Set<IFile>> requirementsEntry = requirementsIter.next();
+ requirementsEntry.getValue().remove(pom);
+ if(requirementsEntry.getValue().isEmpty()) {
+ // was last project that required this capability
+ requirementsIter.remove();
+ }
+ }
+ if(keysEntry.getValue().isEmpty()) {
+ // was last project that required this capability versionless key
+ keysIter.remove();
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistry.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistry.java
new file mode 100644
index 00000000..0ea78e23
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistry.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.project.MavenProjectChangedEvent;
+
+
+/**
+ * Registry of all Maven workspace projects and their inter-dependencies. Dependencies are modelled as generic
+ * requirement/capability match and can represent any dependencies, not just Maven. The only way to change registry
+ * contents is via {@link #apply(MutableProjectRegistry)} call. This class is thread safe.
+ *
+ * @author Igor Fedorenko
+ */
+public class ProjectRegistry extends BasicProjectRegistry implements Serializable, IProjectRegistry {
+
+ private static final long serialVersionUID = -5813062417528479711L;
+
+ private transient int version;
+
+ public synchronized MavenProjectFacade getProjectFacade(IFile pom) {
+ return super.getProjectFacade(pom);
+ }
+
+ public synchronized MavenProjectFacade getProjectFacade(String groupId, String artifactId, String version) {
+ return super.getProjectFacade(groupId, artifactId, version);
+ }
+
+ public synchronized MavenProjectFacade[] getProjects() {
+ return super.getProjects();
+ }
+
+ public synchronized IFile getWorkspaceArtifact(ArtifactKey key) {
+ return super.getWorkspaceArtifact(key);
+ }
+
+ public synchronized List<MavenProjectChangedEvent> apply(MutableProjectRegistry newState)
+ throws StaleMutableProjectRegistryException {
+ if(newState.isStale()) {
+ throw new StaleMutableProjectRegistryException();
+ }
+
+ ArrayList<MavenProjectChangedEvent> events = new ArrayList<MavenProjectChangedEvent>();
+
+ // removed projects
+ for(MavenProjectFacade facade : workspacePoms.values()) {
+ if(!newState.workspacePoms.containsKey(facade.getPom())) {
+ MavenProjectChangedEvent event = new MavenProjectChangedEvent( //
+ facade.getPom(), //
+ MavenProjectChangedEvent.KIND_REMOVED, //
+ MavenProjectChangedEvent.FLAG_NONE, //
+ facade /*old*/, //
+ null /*new*/);
+ events.add(event);
+ }
+ }
+
+ // changed and new projects
+ for(MavenProjectFacade facade : newState.workspacePoms.values()) {
+ MavenProjectFacade old = workspacePoms.get(facade.getPom());
+ if(facade != old) { // not the same instance!
+ MavenProjectChangedEvent event;
+ if(old != null) {
+ int flags = hasDependencyChange(old.getPom(), newState) ? MavenProjectChangedEvent.FLAG_DEPENDENCIES
+ : MavenProjectChangedEvent.FLAG_NONE;
+ event = new MavenProjectChangedEvent(facade.getPom(), //
+ MavenProjectChangedEvent.KIND_CHANGED, //
+ flags, //
+ old /*old*/, //
+ facade /*new*/);
+
+ } else {
+ event = new MavenProjectChangedEvent(facade.getPom(), //
+ MavenProjectChangedEvent.KIND_ADDED, //
+ MavenProjectChangedEvent.FLAG_NONE, //
+ null /*old*/, //
+ facade /*new*/);
+ }
+ events.add(event);
+ }
+ }
+
+ replaceWith(newState);
+
+ version++ ;
+
+ return events;
+ }
+
+ public synchronized int getVersion() {
+ return version;
+ }
+
+ private boolean hasDependencyChange(IFile pom, MutableProjectRegistry newState) {
+ Set<RequiredCapability> oldRequirements = getProjectRequirements(pom);
+ Set<RequiredCapability> requirements = newState.getProjectRequirements(pom);
+
+ return ProjectRegistryManager.hasDiff(oldRequirements, requirements);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryManager.java
new file mode 100644
index 00000000..d1d708b1
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryManager.java
@@ -0,0 +1,854 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.osgi.service.prefs.BackingStoreException;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ProjectScope;
+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.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.osgi.util.NLS;
+
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+import org.apache.maven.artifact.repository.MavenArtifactRepository;
+import org.apache.maven.execution.DefaultMavenExecutionRequest;
+import org.apache.maven.execution.DefaultMavenExecutionResult;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Parent;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.artifact.MavenMetadataCache;
+import org.apache.maven.properties.internal.EnvironmentUtils;
+import org.apache.maven.repository.DelegatingLocalArtifactRepository;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.internal.ExtensionReader;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.embedder.MavenImpl;
+import org.eclipse.m2e.core.internal.lifecycle.LifecycleMappingFactory;
+import org.eclipse.m2e.core.internal.project.DependencyResolutionContext;
+import org.eclipse.m2e.core.internal.project.IManagedCache;
+import org.eclipse.m2e.core.internal.project.MissingLifecycleMapping;
+import org.eclipse.m2e.core.internal.project.MojoExecutionProjectConfigurator;
+import org.eclipse.m2e.core.project.IMavenMarkerManager;
+import org.eclipse.m2e.core.project.IMavenProjectChangedListener;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectChangedEvent;
+import org.eclipse.m2e.core.project.MavenUpdateRequest;
+import org.eclipse.m2e.core.project.ResolverConfiguration;
+import org.eclipse.m2e.core.project.configurator.CustomizableLifecycleMapping;
+import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator;
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+import org.eclipse.m2e.core.project.configurator.NoopLifecycleMapping;
+
+/**
+ * This class keeps track of all maven projects present in the workspace and
+ * provides mapping between Maven and the workspace.
+ */
+public class ProjectRegistryManager {
+
+ public static boolean DEBUG = MavenPlugin.getDefault().isDebugging()
+ & Boolean.parseBoolean(Platform.getDebugOption(IMavenConstants.PLUGIN_ID + "/debug/projectManager")); //$NON-NLS-1$
+
+ static final String ARTIFACT_TYPE_POM = "pom"; //$NON-NLS-1$
+ static final String ARTIFACT_TYPE_JAR = "jar"; //$NON-NLS-1$
+ public static final String ARTIFACT_TYPE_JAVA_SOURCE = "java-source"; //$NON-NLS-1$
+ public static final String ARTIFACT_TYPE_JAVADOC = "javadoc"; //$NON-NLS-1$
+
+ private static final String P_VERSION = "version"; //$NON-NLS-1$
+ private static final String P_RESOLVE_WORKSPACE_PROJECTS = "resolveWorkspaceProjects"; //$NON-NLS-1$
+ private static final String P_ACTIVE_PROFILES = "activeProfiles"; //$NON-NLS-1$
+
+ private static final String VERSION = "1"; //$NON-NLS-1$
+
+ /**
+ * Path of project metadata files, relative to the project. These
+ * files are used to determine if project dependencies need to be
+ * updated.
+ *
+ * Note that path of pom.xml varies for nested projects and pom.xml
+ * are treated separately.
+ */
+ public static final List<? extends IPath> METADATA_PATH = Arrays.asList( //
+ new Path(".project"), // //$NON-NLS-1$
+ new Path(".classpath"), // //$NON-NLS-1$
+ new Path(".settings/org.eclipse.m2e.prefs")); // dirty trick! //$NON-NLS-1$
+
+ private final ProjectRegistry projectRegistry;
+
+ private final MavenConsole console;
+ private final MavenImpl maven;
+
+ private final IMavenMarkerManager markerManager;
+
+ private final ProjectRegistryReader stateReader;
+
+ private final Set<IMavenProjectChangedListener> projectChangeListeners = new LinkedHashSet<IMavenProjectChangedListener>();
+
+ private volatile Thread syncRefreshThread;
+
+ public ProjectRegistryManager(MavenImpl maven, MavenConsole console, File stateLocationDir, boolean readState,
+ IMavenMarkerManager mavenMarkerManager) {
+ this.console = console;
+ this.markerManager = mavenMarkerManager;
+ this.maven = maven;
+
+ this.stateReader = new ProjectRegistryReader(stateLocationDir);
+
+ ProjectRegistry state = readState && stateReader != null ? stateReader.readWorkspaceState(this) : null;
+ this.projectRegistry = (state != null && state.isValid()) ? state : new ProjectRegistry();
+ }
+
+ /**
+ * Creates or returns cached MavenProjectFacade for the given project.
+ *
+ * This method will not block if called from IMavenProjectChangedListener#mavenProjectChanged
+ */
+ public MavenProjectFacade create(IProject project, IProgressMonitor monitor) {
+ return create(getPom(project), false, monitor);
+ }
+
+ /**
+ * Returns MavenProjectFacade corresponding to the pom.
+ *
+ * This method first looks in the project cache, then attempts to load
+ * the pom if the pom is not found in the cache. In the latter case,
+ * workspace resolution is assumed to be enabled for the pom but the pom
+ * will not be added to the cache.
+ */
+ public MavenProjectFacade create(IFile pom, boolean load, IProgressMonitor monitor) {
+ if(pom == null) {
+ return null;
+ }
+
+ // MavenProjectFacade projectFacade = (MavenProjectFacade) workspacePoms.get(pom.getFullPath());
+ MavenProjectFacade projectFacade = projectRegistry.getProjectFacade(pom);
+ if(projectFacade == null && load) {
+ ResolverConfiguration configuration = readResolverConfiguration(pom.getProject());
+ //this used to just pass in 'true' for 'offline'. when the local repo was removed or
+ //corrupted, though, the project wouldn't load correctly
+ IMavenConfiguration mavenConfiguration = MavenPlugin.getDefault().getMavenConfiguration();
+ boolean isOffline = mavenConfiguration.isOffline();
+ MavenExecutionResult executionResult = readProjectWithDependencies(projectRegistry, pom, configuration, //
+ new MavenUpdateRequest(isOffline, false /* updateSnapshots */),
+ monitor);
+ MavenProject mavenProject = executionResult.getProject();
+ if(mavenProject != null) {
+ projectFacade = new MavenProjectFacade(this, pom, mavenProject, configuration, null);
+ } else {
+ List<Throwable> exceptions = executionResult.getExceptions();
+ if (exceptions != null) {
+ for(Throwable ex : exceptions) {
+ String msg = "Failed to read Maven project";
+ console.logError(msg);
+ console.logError(ex.toString());
+ MavenLogger.log(msg, ex);
+ }
+ }
+ }
+ }
+ return projectFacade;
+ }
+
+ public boolean saveResolverConfiguration(IProject project, ResolverConfiguration configuration) {
+ IScopeContext projectScope = new ProjectScope(project);
+ IEclipsePreferences projectNode = projectScope.getNode(IMavenConstants.PLUGIN_ID);
+ if(projectNode != null) {
+ projectNode.put(P_VERSION, VERSION);
+
+ projectNode.putBoolean(P_RESOLVE_WORKSPACE_PROJECTS, configuration.shouldResolveWorkspaceProjects());
+
+ projectNode.put(P_ACTIVE_PROFILES, configuration.getActiveProfiles());
+
+ try {
+ projectNode.flush();
+ return true;
+ } catch(BackingStoreException ex) {
+ MavenLogger.log("Failed to save resolver configuration", ex);
+ }
+ }
+
+ return false;
+ }
+
+ public ResolverConfiguration readResolverConfiguration(IProject project) {
+ IScopeContext projectScope = new ProjectScope(project);
+ IEclipsePreferences projectNode = projectScope.getNode(IMavenConstants.PLUGIN_ID);
+ if(projectNode==null) {
+ return new ResolverConfiguration();
+ }
+
+ String version = projectNode.get(P_VERSION, null);
+ if(version == null) { // migrate from old config
+ // return LegacyBuildPathManager.getResolverConfiguration(project);
+ return new ResolverConfiguration();
+ }
+
+ ResolverConfiguration configuration = new ResolverConfiguration();
+ configuration.setResolveWorkspaceProjects(projectNode.getBoolean(P_RESOLVE_WORKSPACE_PROJECTS, false));
+
+ configuration.setActiveProfiles(projectNode.get(P_ACTIVE_PROFILES, "")); //$NON-NLS-1$
+ return configuration;
+ }
+
+ IFile getPom(IProject project) {
+ if (project == null || !project.isAccessible()) {
+ // XXX sensible handling
+ return null;
+ }
+ return project.getFile(IMavenConstants.POM_FILE_NAME);
+ }
+
+ /**
+ * Removes specified poms from the cache.
+ * Adds dependent poms to pomSet but does not directly refresh dependent poms.
+ * Recursively removes all nested modules if appropriate.
+ *
+ * @return a {@link Set} of {@link IFile} affected poms
+ */
+ public Set<IFile> remove(MutableProjectRegistry state, Set<IFile> poms, boolean force) {
+ Set<IFile> pomSet = new LinkedHashSet<IFile>();
+ for (Iterator<IFile> it = poms.iterator(); it.hasNext(); ) {
+ IFile pom = it.next();
+ MavenProjectFacade facade = state.getProjectFacade(pom);
+ if (force || facade == null || facade.isStale()) {
+ pomSet.addAll(remove(state, pom));
+ }
+ }
+ return pomSet;
+ }
+
+ /**
+ * Removes the pom from the cache.
+ * Adds dependent poms to pomSet but does not directly refresh dependent poms.
+ * Recursively removes all nested modules if appropriate.
+ *
+ * @return a {@link Set} of {@link IFile} affected poms
+ */
+ public Set<IFile> remove(MutableProjectRegistry state, IFile pom) {
+ MavenProjectFacade facade = state.getProjectFacade(pom);
+ ArtifactKey mavenProject = facade != null ? facade.getArtifactKey() : null;
+
+ flushCaches(pom, facade);
+
+ if (mavenProject == null) {
+ state.removeProject(pom, null);
+ return Collections.emptySet();
+ }
+
+ Set<IFile> pomSet = new LinkedHashSet<IFile>();
+
+ pomSet.addAll(state.getDependents(MavenCapability.createMaven(mavenProject), false));
+ pomSet.addAll(state.getDependents(MavenCapability.createMavenParent(mavenProject), false)); // TODO check packaging
+ state.removeProject(pom, mavenProject);
+
+ pomSet.addAll(refreshWorkspaceModules(state, pom, mavenProject));
+
+ pomSet.remove(pom);
+
+ return pomSet;
+ }
+
+ private void flushCaches(IFile pom, MavenProjectFacade facade) {
+ ArtifactKey key = null;
+ MavenProject project = null;
+
+ if (facade != null) {
+ key = facade.getArtifactKey();
+ project = facade.getMavenProject();
+ }
+ try {
+ IManagedCache cache = (IManagedCache) maven.getPlexusContainer().lookup(MavenMetadataCache.class);
+ cache.removeProject(pom, key);
+ } catch(ComponentLookupException ex) {
+ // can't really happen
+ } catch(CoreException ex) {
+ // can't really happen
+ }
+ if (project != null) {
+ getMaven().xxxRemoveExtensionsRealm(project);
+ }
+ }
+
+ /**
+ * This method acquires workspace root's lock and sends project change events.
+ * It is meant for synchronous registry updates.
+ */
+ public void refresh(MavenUpdateRequest request, IProgressMonitor monitor) throws CoreException {
+ SubMonitor progress = SubMonitor.convert(monitor, Messages.ProjectRegistryManager_task_refreshing, 100);
+ ISchedulingRule rule = ResourcesPlugin.getWorkspace().getRoot();
+ Job.getJobManager().beginRule(rule, progress);
+ try {
+ syncRefreshThread = Thread.currentThread();
+
+ MutableProjectRegistry newState = newMutableProjectRegistry();
+ try {
+ refresh(newState, request, progress.newChild(95));
+
+ applyMutableProjectRegistry(newState, progress.newChild(5));
+ } finally {
+ newState.close();
+ }
+ } finally {
+ syncRefreshThread = null;
+ Job.getJobManager().endRule(rule);
+ }
+ }
+
+ void refresh(MutableProjectRegistry newState, MavenUpdateRequest updateRequest, IProgressMonitor monitor) throws CoreException {
+ MavenExecutionRequest executionRequest = getMaven().createExecutionRequest(monitor);
+
+ DependencyResolutionContext context = new DependencyResolutionContext(updateRequest, executionRequest);
+
+ refresh(newState, context, monitor);
+ }
+
+ protected void refresh(MutableProjectRegistry newState, DependencyResolutionContext context, IProgressMonitor monitor)
+ throws CoreException {
+ while(!context.isEmpty()) {
+ Map<IFile, MavenProjectFacade> newFacades = new LinkedHashMap<IFile, MavenProjectFacade>();
+
+ // phase 1: build projects without dependencies and populate workspace with known projects
+ while(!context.isEmpty()) {
+ if(monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+
+ if(newState.isStale() || (syncRefreshThread != null && syncRefreshThread != Thread.currentThread())) {
+ throw new StaleMutableProjectRegistryException();
+ }
+
+ IFile pom = context.pop();
+
+ monitor.subTask(NLS.bind(Messages.ProjectRegistryManager_task_project, pom.getProject().getName()));
+ MavenProjectFacade newFacade = null;
+ if(pom.isAccessible() && pom.getProject().hasNature(IMavenConstants.NATURE_ID)) {
+ MavenProjectFacade oldFacade = newState.getProjectFacade(pom);
+
+ if(!context.isForce(pom) && oldFacade != null && !oldFacade.isStale()) {
+ // skip refresh if not forced and up-to-date facade
+ continue;
+ }
+
+ flushCaches(pom, oldFacade);
+
+ newFacade = readMavenProject(pom, context, newState, monitor);
+ }
+
+ newState.setProject(pom, newFacade);
+
+ // at this point project facade and project capabilities/requirements are inconsistent in the state
+ // this will be reconciled during the second phase
+
+ newFacades.put(pom, newFacade); // stash work for the second phase
+ }
+
+ // TODO theoretically, there is no need to re-read projects during second resolution phase
+ // only re-resolve dependencies.
+
+ // phase 2: resolve project dependencies
+ for(Map.Entry<IFile, MavenProjectFacade> entry : newFacades.entrySet()) {
+ if(monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+
+ if(newState.isStale() || (syncRefreshThread != null && syncRefreshThread != Thread.currentThread())) {
+ throw new StaleMutableProjectRegistryException();
+ }
+
+ IFile pom = entry.getKey();
+ MavenProjectFacade newFacade = entry.getValue();
+
+ Set<Capability> capabilities = null;
+ Set<RequiredCapability> requirements = null;
+ if(newFacade != null) {
+ monitor.subTask(NLS.bind(Messages.ProjectRegistryManager_task_project,newFacade.getProject().getName()));
+
+ // TODO is this expansive?
+ MavenExecutionRequest mavenRequest = getConfiguredExecutionRequest(context, newState, newFacade.getPom(),
+ newFacade.getResolverConfiguration());
+ mavenRequest.getProjectBuildingRequest().setProject(newFacade.getMavenProject());
+ mavenRequest.getProjectBuildingRequest().setResolveDependencies(true);
+
+ capabilities = new LinkedHashSet<Capability>();
+ requirements = new LinkedHashSet<RequiredCapability>();
+
+ Capability mavenParentCapability = MavenCapability.createMavenParent(newFacade.getArtifactKey());
+
+ // maven projects always have these capabilities
+ capabilities.add(MavenCapability.createMaven(newFacade.getArtifactKey()));
+ capabilities.add(mavenParentCapability); // TODO consider packaging
+
+ AbstractMavenDependencyResolver resolver = getMavenDependencyResolver(newFacade, monitor);
+ resolver.setContextProjectRegistry(newState);
+ try {
+ resolver.resolveProjectDependencies(newFacade, mavenRequest, capabilities, requirements, monitor);
+ } finally {
+ resolver.setContextProjectRegistry(null);
+ }
+
+ newFacade.setMavenProjectArtifacts();
+
+ // always refresh child modules
+ context.forcePomFiles(newState.getDependents(mavenParentCapability, true));
+ } else {
+ if(pom.isAccessible() && pom.getProject().hasNature(IMavenConstants.NATURE_ID)) {
+ try {
+ // MNGECLIPSE-605 embedder is not able to resolve the project due to missing configuration in the parent
+ Model model = getMaven().readModel(pom.getLocation().toFile());
+ if(model != null && model.getParent() != null) {
+ Parent parent = model.getParent();
+ if(parent.getGroupId() != null && parent.getArtifactId() != null && parent.getVersion() != null) {
+ ArtifactKey parentKey = new ArtifactKey(parent.getGroupId(), parent.getArtifactId(),
+ parent.getVersion(), null);
+ requirements = new HashSet<RequiredCapability>();
+ requirements.add(MavenRequiredCapability.createMavenParent(parentKey));
+ }
+ }
+ } catch(Exception ex) {
+ // we've tried our best, there is nothing else we can do
+ }
+ }
+ }
+
+ Set<Capability> oldCapabilities = newState.setCapabilities(pom, capabilities);
+ // if our capabilities changed, recalculate everyone who depends on new/changed/removed capabilities
+ Set<Capability> changedCapabilities = diff(oldCapabilities, capabilities);
+ for(Capability capability : changedCapabilities) {
+ context.forcePomFiles(newState.getDependents(capability, true));
+ }
+
+ Set<RequiredCapability> oldRequirements = newState.setRequirements(pom, requirements);
+ // if our dependencies changed, recalculate everyone who depends on us
+ // this is needed to deal with transitive dependency resolution in maven
+ if(oldCapabilities != null && hasDiff(oldRequirements, requirements)) {
+ for(Capability capability : oldCapabilities) {
+ context.forcePomFiles(newState.getDependents(capability.getVersionlessKey(), true));
+ }
+ }
+
+ monitor.worked(1);
+ }
+ }
+ }
+
+ static <T> Set<T> diff(Set<T> a, Set<T> b) {
+ if(a == null || a.isEmpty()) {
+ if(b == null || b.isEmpty()) {
+ return Collections.emptySet();
+ }
+ return b;
+ }
+ if(b == null || b.isEmpty()) {
+ return a;
+ }
+ Set<T> result = new HashSet<T>();
+ Set<T> t;
+
+ t = new HashSet<T>(a); t.removeAll(b); result.addAll(t);
+ t = new HashSet<T>(b); t.removeAll(a); result.addAll(t);
+
+ return result;
+ }
+
+ static <T> boolean hasDiff(Set<T> a, Set<T> b) {
+ if(a == null || a.isEmpty()) {
+ return b != null && !b.isEmpty();
+ }
+
+ if(b == null || b.isEmpty()) {
+ return true;
+ }
+
+ if(a.size() != b.size()) {
+ return true;
+ }
+
+ Iterator<T> oldIter = a.iterator();
+ Iterator<T> iter = b.iterator();
+
+ while(oldIter.hasNext()) {
+ T oldRequirement = oldIter.next();
+ T requirement = iter.next();
+ if (!oldRequirement.equals(requirement)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private AbstractMavenDependencyResolver getMavenDependencyResolver(MavenProjectFacade newFacade, IProgressMonitor monitor) throws CoreException {
+ ILifecycleMapping lifecycleMapping = newFacade.getLifecycleMapping(monitor);
+
+ if (lifecycleMapping instanceof ILifecycleMapping2) {
+ AbstractMavenDependencyResolver resolver = ((ILifecycleMapping2) lifecycleMapping).getDependencyResolver(monitor);
+ resolver.setManager(this);
+ return resolver;
+ }
+
+ return new DefaultMavenDependencyResolver(this, markerManager);
+ }
+
+ protected MavenExecutionRequest getConfiguredExecutionRequest(DependencyResolutionContext context,
+ MutableProjectRegistry state, IFile pom, ResolverConfiguration resolverConfiguration) throws CoreException {
+ MavenExecutionRequest mavenRequest = DefaultMavenExecutionRequest.copy(context.getExecutionRequest());
+ configureExecutionRequest(mavenRequest, state, pom, resolverConfiguration);
+ getMaven().populateDefaults(mavenRequest);
+ mavenRequest.setOffline(context.getRequest().isOffline());
+ return mavenRequest;
+ }
+
+ private MavenProjectFacade readMavenProject(IFile pom, DependencyResolutionContext context,
+ MutableProjectRegistry state, IProgressMonitor monitor) throws CoreException {
+ markerManager.deleteMarkers(pom, IMavenConstants.MARKER_POM_LOADING_ID);
+
+ ResolverConfiguration resolverConfiguration = readResolverConfiguration(pom.getProject());
+
+ MavenProject mavenProject = null;
+ MavenExecutionResult mavenResult = null;
+ if (pom.isAccessible()) {
+ MavenExecutionRequest mavenRequest = getConfiguredExecutionRequest(context, state, pom, resolverConfiguration);
+ mavenResult = getMaven().readProject(mavenRequest, monitor);
+ mavenProject = mavenResult.getProject();
+ }
+
+ markerManager.addEditorHintMarkers(pom, IMavenConstants.MARKER_POM_LOADING_ID);
+ if (mavenProject == null) {
+ markerManager.addMarkers(pom, IMavenConstants.MARKER_POM_LOADING_ID, mavenResult);
+ return null;
+ }
+
+ ILifecycleMapping lifecycleMapping = getLifecycleMapping(pom, mavenProject, resolverConfiguration, monitor);
+
+ // don't cache maven session
+ getMaven().detachFromSession(mavenProject);
+
+ // create and return new project facade
+ MavenProjectFacade mavenProjectFacade = new MavenProjectFacade(ProjectRegistryManager.this, pom, mavenProject,
+ resolverConfiguration, lifecycleMapping);
+
+ MavenPlugin.getDefault().getProjectConfigurationManager().validateProjectConfiguration(mavenProjectFacade, monitor);
+
+ return mavenProjectFacade;
+ }
+
+ MavenExecutionPlan calculateExecutionPlan(MavenProjectFacade facade, IProgressMonitor monitor) throws CoreException {
+ return calculateExecutionPlan(projectRegistry, facade, monitor);
+ }
+
+ private MavenExecutionPlan calculateExecutionPlan(IProjectRegistry state, MavenProjectFacade facade, IProgressMonitor monitor) throws CoreException {
+ MavenExecutionRequest request = createExecutionRequest(state, facade.getPom(), facade.getResolverConfiguration(), monitor);
+ request.setGoals(Arrays.asList("deploy")); //$NON-NLS-1$
+ return getMaven().calculateExecutionPlan(request, facade.getMavenProject(monitor), monitor);
+ }
+
+ public IFile getModulePom(IFile pom, String moduleName) {
+ return pom.getParent().getFile(new Path(moduleName).append(IMavenConstants.POM_FILE_NAME));
+ }
+
+ private Set<IFile> refreshWorkspaceModules(MutableProjectRegistry state, IFile pom, ArtifactKey mavenProject) {
+ if (mavenProject == null) {
+ return Collections.emptySet();
+ }
+
+ return state.removeWorkspaceModules(pom, mavenProject);
+ }
+
+ public void addMavenProjectChangedListener(IMavenProjectChangedListener listener) {
+ synchronized (projectChangeListeners) {
+ projectChangeListeners.add(listener);
+ }
+ }
+
+ public void removeMavenProjectChangedListener(IMavenProjectChangedListener listener) {
+ if(listener == null) {
+ return;
+ }
+ synchronized (projectChangeListeners) {
+ projectChangeListeners.remove(listener);
+ }
+ }
+
+ public void notifyProjectChangeListeners(List<MavenProjectChangedEvent> events, IProgressMonitor monitor) {
+ if(events.size() > 0) {
+ MavenProjectChangedEvent[] eventsArray = events.toArray(new MavenProjectChangedEvent[events.size()]);
+ ArrayList<IMavenProjectChangedListener> listeners = new ArrayList<IMavenProjectChangedListener>();
+ synchronized(this.projectChangeListeners) {
+ listeners.addAll(this.projectChangeListeners);
+ }
+ listeners.addAll(ExtensionReader.readProjectChangedEventListenerExtentions());
+ for(IMavenProjectChangedListener listener : listeners) {
+ listener.mavenProjectChanged(eventsArray, monitor);
+ }
+ }
+ }
+
+ public MavenProjectFacade getMavenProject(String groupId, String artifactId, String version) {
+ return projectRegistry.getProjectFacade(groupId, artifactId, version);
+ }
+
+ MavenExecutionResult readProjectWithDependencies(IFile pomFile, ResolverConfiguration resolverConfiguration,
+ MavenUpdateRequest updateRequest, IProgressMonitor monitor) {
+ return readProjectWithDependencies(projectRegistry, pomFile, resolverConfiguration, updateRequest, monitor);
+ }
+
+ private MavenExecutionResult readProjectWithDependencies(IProjectRegistry state, IFile pomFile, ResolverConfiguration resolverConfiguration,
+ MavenUpdateRequest updateRequest, IProgressMonitor monitor) {
+
+ try {
+ MavenExecutionRequest request = createExecutionRequest(state, pomFile, resolverConfiguration, monitor);
+ getMaven().populateDefaults(request);
+ request.setOffline(updateRequest.isOffline());
+ request.getProjectBuildingRequest().setResolveDependencies(true);
+ return getMaven().readProject(request, monitor);
+ } catch(CoreException ex) {
+ DefaultMavenExecutionResult result = new DefaultMavenExecutionResult();
+ result.addException(ex);
+ return result;
+ }
+
+ }
+
+ public IMavenProjectFacade[] getProjects() {
+ return projectRegistry.getProjects();
+ }
+
+ public IMavenProjectFacade getProject(IProject project) {
+ return projectRegistry.getProjectFacade(getPom(project));
+ }
+
+ public boolean setResolverConfiguration(IProject project, ResolverConfiguration configuration) {
+ MavenProjectFacade projectFacade = create(project, new NullProgressMonitor());
+ if(projectFacade!=null) {
+ projectFacade.setResolverConfiguration(configuration);
+ }
+ return saveResolverConfiguration(project, configuration);
+ }
+
+ /**
+ * Context
+ */
+ static class Context {
+ final IProjectRegistry state;
+
+ final ResolverConfiguration resolverConfiguration;
+
+ final IFile pom;
+
+ Context(IProjectRegistry state, ResolverConfiguration resolverConfiguration, IFile pom) {
+ this.state = state;
+ this.resolverConfiguration = resolverConfiguration;
+ this.pom = pom;
+ }
+ }
+
+ public MavenExecutionRequest createExecutionRequest(IFile pom, ResolverConfiguration resolverConfiguration, IProgressMonitor monitor) throws CoreException {
+ return createExecutionRequest(projectRegistry, pom, resolverConfiguration, monitor);
+ }
+
+ private MavenExecutionRequest createExecutionRequest(IProjectRegistry state, IFile pom, ResolverConfiguration resolverConfiguration, IProgressMonitor monitor) throws CoreException {
+ MavenExecutionRequest request = getMaven().createExecutionRequest(monitor);
+
+ return configureExecutionRequest(request, state, pom, resolverConfiguration);
+ }
+
+ private MavenExecutionRequest configureExecutionRequest(MavenExecutionRequest request, IProjectRegistry state,
+ IFile pom, ResolverConfiguration resolverConfiguration) throws CoreException {
+ request.setPom(pom.getLocation().toFile());
+
+ request.addActiveProfiles(resolverConfiguration.getActiveProfileList());
+
+ // temporary solution for https://issues.sonatype.org/browse/MNGECLIPSE-1607
+ Properties systemProperties = new Properties();
+ EnvironmentUtils.addEnvVars(systemProperties);
+ systemProperties.putAll(System.getProperties());
+ request.setSystemProperties(systemProperties);
+
+ // eclipse workspace repository implements both workspace dependency resolution
+ // and inter-module dependency resolution for multi-module projects.
+
+ request.setLocalRepository(getMaven().getLocalRepository());
+ request.setWorkspaceReader(getWorkspaceReader(state, pom, resolverConfiguration));
+
+ return request;
+ }
+
+ private EclipseWorkspaceArtifactRepository getWorkspaceReader(IProjectRegistry state, IFile pom,
+ ResolverConfiguration resolverConfiguration) {
+ Context context = new Context(state, resolverConfiguration, pom);
+ EclipseWorkspaceArtifactRepository workspaceReader = new EclipseWorkspaceArtifactRepository(context);
+ return workspaceReader;
+ }
+
+ public MavenArtifactRepository getWorkspaceLocalRepository() throws CoreException {
+ ResolverConfiguration resolverConfiguration = new ResolverConfiguration();
+ resolverConfiguration.setResolveWorkspaceProjects(true);
+ EclipseWorkspaceArtifactRepository workspaceReader = getWorkspaceReader(projectRegistry, null,
+ resolverConfiguration);
+
+ DelegatingLocalArtifactRepository localRepo = new DelegatingLocalArtifactRepository(getMaven().getLocalRepository());
+ localRepo.setIdeWorkspace(workspaceReader);
+
+ return localRepo;
+ }
+
+ MutableProjectRegistry newMutableProjectRegistry() {
+ return new MutableProjectRegistry(projectRegistry);
+ }
+
+ /**
+ * Applies mutable project registry to the primary project registry and
+ * and corresponding MavenProjectChangedEvent's to all registered
+ * IMavenProjectChangedListener's.
+ *
+ * This method must be called from a thread holding workspace root's lock.
+ *
+ * @throws StaleMutableProjectRegistryException if primary project registry
+ * was modified after mutable registry has been created
+ */
+ void applyMutableProjectRegistry(MutableProjectRegistry newState, IProgressMonitor monitor) {
+ List<MavenProjectChangedEvent> events = projectRegistry.apply(newState);
+ stateReader.writeWorkspaceState(projectRegistry);
+ notifyProjectChangeListeners(events, monitor);
+ }
+
+ IMaven getMaven() {
+ return maven;
+ }
+
+
+ ILifecycleMapping getLifecycleMapping(IFile pom, MavenProject project, ResolverConfiguration resolverConfiguration, IProgressMonitor monitor) {
+ String mappingId = null;
+
+ if (project.equals(pom.getParent())) {
+ throw new IllegalArgumentException("Nested workspace module " + pom); //$NON-NLS-1$
+ }
+
+ if ("pom".equals(project.getPackaging())) { //$NON-NLS-1$
+ return new NoopLifecycleMapping();
+ }
+
+ Plugin plugin = project.getPlugin( "org.eclipse.m2e:lifecycle-mapping" ); //$NON-NLS-1$
+
+ Xpp3Dom configuration = null;
+
+ if (plugin != null) {
+ configuration = (Xpp3Dom) plugin.getConfiguration();
+ if (configuration != null) {
+ Xpp3Dom mappingIdDom = configuration.getChild("mappingId"); //$NON-NLS-1$
+ if (mappingIdDom != null) {
+ mappingId = mappingIdDom.getValue();
+ }
+ }
+ }
+
+ ILifecycleMapping lifecycleMapping = null;
+ if (mappingId == null || mappingId.length() <= 0) {
+ lifecycleMapping = LifecycleMappingFactory.getLifecycleMappingFor(project.getPackaging());
+ } else {
+ lifecycleMapping = LifecycleMappingFactory.getLifecycleMapping(mappingId);
+ }
+
+ if(configuration != null && lifecycleMapping instanceof CustomizableLifecycleMapping) {
+ CustomizableLifecycleMapping custmizableMapping = (CustomizableLifecycleMapping) lifecycleMapping;
+
+ Xpp3Dom configuratorsDom = configuration.getChild("configurators"); //$NON-NLS-1$
+ Xpp3Dom executionsDom = configuration.getChild("mojoExecutions"); //$NON-NLS-1$
+
+ if(configuratorsDom != null) {
+ for(Xpp3Dom configuratorDom : configuratorsDom.getChildren("configurator")) { //$NON-NLS-1$
+ String configuratorId = configuratorDom.getAttribute("id"); //$NON-NLS-1$
+ AbstractProjectConfigurator configurator = LifecycleMappingFactory.getProjectConfigurator(configuratorId);
+ if(configurator == null) {
+ String message = "Configurator '"
+ + configuratorId
+ + "' is not available for project '"
+ + pom.getProject().getName()
+ + "'. To enable full functionality, install the configurator and run Maven->Update Project Configuration.";
+ MavenPlugin.getDefault().getLog().log(new Status(IStatus.WARNING, IMavenConstants.PLUGIN_ID, message));
+ MavenPlugin.getDefault().getConsole().logError(message);
+// throw new IllegalArgumentException(message);
+ } else {
+ custmizableMapping.addConfigurator(configurator);
+ }
+ }
+ }
+
+ if(executionsDom != null) {
+ for(Xpp3Dom execution : executionsDom.getChildren("mojoExecution")) { //$NON-NLS-1$
+ String strRunOnIncremental = execution.getAttribute("runOnIncremental"); //$NON-NLS-1$
+ custmizableMapping.addConfigurator(MojoExecutionProjectConfigurator.fromString(execution.getValue(),
+ toBool(strRunOnIncremental, true)));
+ }
+ }
+ }
+
+ if (lifecycleMapping == null) {
+ // Do not create error marker here - it is created in ProjectConfigurationManager.validateLifecycleMappingConfiguration
+ String msg = "Project " + pom.getProject().getName() + " uses unknown or missing lifecycle mapping with id='"
+ + mappingId + "', project packaging type='" + project.getPackaging() + "'.";
+ //Exception e = new Exception(msg);
+ //MavenLogger.log(msg, e);
+ console.logError(msg);
+ return new MissingLifecycleMapping(mappingId);
+ }
+
+ return lifecycleMapping;
+ }
+
+ private boolean toBool(String value, boolean def) {
+ if(value == null || value.length() == 0) {
+ return def;
+ }
+ return Boolean.parseBoolean(value);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryReader.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryReader.java
new file mode 100644
index 00000000..56452fae
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryReader.java
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.osgi.service.resolver.VersionRange;
+
+import org.codehaus.plexus.util.IOUtil;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+
+
+/**
+ * Workspace state reader
+ *
+ * @author Eugene Kuleshov
+ */
+public class ProjectRegistryReader {
+
+ private static final String WORKSPACE_STATE = "workspaceState.ser"; //$NON-NLS-1$
+
+ private final File stateFile;
+
+ private static PackageAdmin packageAdmin;
+
+ public ProjectRegistryReader(File stateLocationDir) {
+ this.stateFile = new File(stateLocationDir, WORKSPACE_STATE);
+ }
+
+ public ProjectRegistry readWorkspaceState(final ProjectRegistryManager managerImpl) {
+ if(stateFile.exists()) {
+ final PackageAdmin packageAdmin = getPackageAdmin();
+ ObjectInputStream is = null;
+ try {
+ is = new ObjectInputStream(new BufferedInputStream(new FileInputStream(stateFile))) {
+ {
+ enableResolveObject(true);
+ }
+
+ protected Object resolveObject(Object o) throws IOException {
+ if(o instanceof IPathReplace) {
+ return ((IPathReplace) o).getPath();
+ } else if(o instanceof IFileReplace) {
+ return ((IFileReplace) o).getFile();
+ } else if(o instanceof MavenProjectManagerImplReplace) {
+ return managerImpl;
+ }
+ return super.resolveObject(o);
+ }
+
+ protected java.lang.Class<?> resolveClass(java.io.ObjectStreamClass desc) throws IOException,
+ ClassNotFoundException {
+ String symbolicName = (String) readObject();
+ if(symbolicName == null) {
+ return super.resolveClass(desc);
+ }
+ String versionStr = (String) readObject();
+ Version version = Version.parseVersion(versionStr);
+ VersionRange versionRange = new VersionRange(version, true, version, true);
+ Bundle[] bundles = packageAdmin.getBundles(symbolicName, versionRange.toString());
+ if(bundles == null || bundles.length != 1) {
+ throw new ClassNotFoundException("Could not find bundle " + symbolicName + "/" + version //$NON-NLS-1$ //$NON-NLS-2$
+ + " required to load class " + desc.getName()); //$NON-NLS-1$
+ }
+ return bundles[0].loadClass(desc.getName());
+ };
+ };
+ return (ProjectRegistry) is.readObject();
+ } catch(Exception ex) {
+ MavenLogger.log("Can't read workspace state", ex);
+ } finally {
+ IOUtil.close(is);
+ }
+ }
+ return null;
+ }
+
+ private static synchronized PackageAdmin getPackageAdmin() {
+ // TODO inject dependencies already!
+ if(packageAdmin == null) {
+ BundleContext context = MavenPlugin.getDefault().getBundleContext();
+ ServiceReference serviceReference = context.getServiceReference(PackageAdmin.class.getName());
+ packageAdmin = (PackageAdmin) context.getService(serviceReference);
+ }
+ return packageAdmin;
+ }
+
+ public void writeWorkspaceState(ProjectRegistry state) {
+ final ClassLoader thisClassloader = getClass().getClassLoader();
+
+ final PackageAdmin packageAdmin = getPackageAdmin();
+
+ ObjectOutputStream os = null;
+ try {
+ os = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(stateFile))) {
+ {
+ enableReplaceObject(true);
+ }
+
+ protected Object replaceObject(Object o) throws IOException {
+ if(o instanceof IPath) {
+ return new IPathReplace((IPath) o);
+ } else if(o instanceof IFile) {
+ return new IFileReplace((IFile) o);
+ } else if(o instanceof ProjectRegistryManager) {
+ return new MavenProjectManagerImplReplace();
+ }
+ return super.replaceObject(o);
+ }
+
+ protected void annotateClass(java.lang.Class<?> cl) throws IOException {
+ // if the class is visible through this classloader, assume it will be during reading stream back
+ try {
+ Class<?> target = cl;
+ while(target.isArray()) {
+ target = target.getComponentType();
+ }
+
+ if(target.isPrimitive() || target.equals(thisClassloader.loadClass(target.getName()))) {
+ writeObject(null); // TODO is there a better way?
+ return;
+ }
+ } catch(ClassNotFoundException ex) {
+ // fall through
+ }
+
+ // foreign class
+ Bundle bundle = packageAdmin.getBundle(cl);
+ if(bundle != null) {
+ writeObject(bundle.getSymbolicName());
+ writeObject(bundle.getVersion().toString());
+ }
+
+ // TODO this will likely fail during desirialization
+ };
+ };
+ synchronized(state) { // see MNGECLIPSE-860
+ os.writeObject(state);
+ }
+ } catch(Exception ex) {
+ MavenLogger.log("Can't write workspace state", ex);
+ } finally {
+ IOUtil.close(os);
+ }
+ }
+
+ /**
+ * IPath replacement used for object serialization
+ */
+ private static final class IPathReplace implements Serializable {
+ private static final long serialVersionUID = -2361259525684491181L;
+
+ private final String path;
+
+ public IPathReplace(IPath path) {
+ this.path = path.toPortableString();
+ }
+
+ public IPath getPath() {
+ return Path.fromPortableString(path);
+ }
+ }
+
+ /**
+ * IFile replacement used for object serialization
+ */
+ private static final class IFileReplace implements Serializable {
+ private static final long serialVersionUID = -7266001068347075329L;
+
+ private final String path;
+
+ public IFileReplace(IFile file) {
+ this.path = file.getFullPath().toPortableString();
+ }
+
+ public IFile getFile() {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ return root.getFile(Path.fromPortableString(path));
+ }
+ }
+
+ static final class MavenProjectManagerImplReplace implements Serializable {
+ private static final long serialVersionUID = 1995671440438776471L;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryRefreshJob.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryRefreshJob.java
new file mode 100644
index 00000000..ff0eeb51
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/ProjectRegistryRefreshJob.java
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+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.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.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
+import org.eclipse.ui.progress.IProgressConstants;
+
+import org.eclipse.m2e.core.actions.OpenMavenConsoleAction;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.jobs.IBackgroundProcessingQueue;
+import org.eclipse.m2e.core.project.MavenUpdateRequest;
+
+public class ProjectRegistryRefreshJob extends Job implements IResourceChangeListener, IPreferenceChangeListener, IBackgroundProcessingQueue {
+
+ private static final int DELTA_FLAGS = IResourceDelta.CONTENT | IResourceDelta.MOVED_FROM | IResourceDelta.MOVED_TO
+ | IResourceDelta.COPIED_FROM | IResourceDelta.REPLACED;
+
+ private final List<MavenUpdateRequest> queue = new ArrayList<MavenUpdateRequest>();
+
+ private final ProjectRegistryManager manager;
+
+ private final IMavenConfiguration mavenConfiguration;
+
+ private final MavenConsole console;
+
+ public ProjectRegistryRefreshJob(ProjectRegistryManager manager, MavenConsole console, IMavenConfiguration mavenConfiguration) {
+ super(Messages.ProjectRegistryRefreshJob_title);
+ this.manager = manager;
+ this.mavenConfiguration = mavenConfiguration;
+ this.console = console;
+ setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
+ setProperty(IProgressConstants.ACTION_PROPERTY, new OpenMavenConsoleAction());
+ }
+
+ public void refresh(MavenUpdateRequest updateRequest) {
+ queue(updateRequest);
+ schedule(1000L);
+ }
+
+ // Job
+
+ public IStatus run(IProgressMonitor monitor) {
+ monitor.beginTask(Messages.ProjectRegistryRefreshJob_task_refreshing, IProgressMonitor.UNKNOWN);
+ ArrayList<MavenUpdateRequest> requests;
+ synchronized(this.queue) {
+ requests = new ArrayList<MavenUpdateRequest>(this.queue);
+ this.queue.clear();
+ }
+
+ try {
+ MutableProjectRegistry newState = manager.newMutableProjectRegistry();
+ try {
+
+ for (MavenUpdateRequest request : requests) {
+ if(monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+
+ manager.refresh(newState, request, monitor);
+ }
+
+ ISchedulingRule rule = ResourcesPlugin.getWorkspace().getRoot();
+ getJobManager().beginRule(rule, monitor);
+ try {
+ manager.applyMutableProjectRegistry(newState, monitor);
+ } finally {
+ getJobManager().endRule(rule);
+ }
+ } finally {
+ newState.close();
+ }
+
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+
+ } catch(OperationCanceledException ex) {
+ console.logMessage("Refreshing Maven model is canceled");
+
+ } catch (StaleMutableProjectRegistryException e) {
+ synchronized(this.queue) {
+ this.queue.addAll(0, requests);
+ if(!this.queue.isEmpty()) {
+ schedule(1000L);
+ }
+ }
+
+ } catch(Exception ex) {
+ MavenLogger.log(ex.getMessage(), ex);
+
+ } finally {
+ monitor.done();
+
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ // IResourceChangeListener
+
+ public void resourceChanged(IResourceChangeEvent event) {
+ boolean offline = mavenConfiguration.isOffline();
+ boolean updateSnapshots = false;
+
+ int type = event.getType();
+
+ if(IResourceChangeEvent.PRE_CLOSE == type || IResourceChangeEvent.PRE_DELETE == type) {
+ queue(new MavenUpdateRequest((IProject) event.getResource(), //
+ offline, updateSnapshots));
+
+ } else {
+ // if (IResourceChangeEvent.POST_CHANGE == type)
+ IResourceDelta delta = event.getDelta(); // workspace delta
+ IResourceDelta[] projectDeltas = delta.getAffectedChildren();
+ Set<IProject> removeProjects = new LinkedHashSet<IProject>();
+ Set<IProject> refreshProjects = new LinkedHashSet<IProject>();
+ for(int i = 0; i < projectDeltas.length; i++ ) {
+ try {
+ projectChanged(projectDeltas[i], removeProjects, refreshProjects);
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+
+ // XXX consider to run refresh in offline mode when it is triggered by resource change
+ if(!removeProjects.isEmpty()) {
+ IProject[] projects = removeProjects.toArray(new IProject[removeProjects.size()]);
+ MavenUpdateRequest updateRequest = new MavenUpdateRequest(projects, offline, updateSnapshots);
+ updateRequest.setForce(false);
+ queue(updateRequest);
+ console.logMessage("Refreshing " + updateRequest.toString());
+ }
+ if(!refreshProjects.isEmpty()) {
+ IProject[] projects = refreshProjects.toArray(new IProject[refreshProjects.size()]);
+ MavenUpdateRequest updateRequest = new MavenUpdateRequest(projects, offline, updateSnapshots);
+ updateRequest.setForce(false);
+ queue(updateRequest);
+ console.logMessage("Refreshing " + updateRequest.toString());
+ }
+ }
+
+ synchronized(queue) {
+ if(!queue.isEmpty()) {
+ schedule(1000L);
+ }
+ }
+ }
+
+ private void projectChanged(IResourceDelta delta, Set<IProject> removeProjects, final Set<IProject> refreshProjects)
+ throws CoreException {
+ final IProject project = (IProject) delta.getResource();
+
+ for(IPath path : ProjectRegistryManager.METADATA_PATH) {
+ if (delta.findMember(path) != null) {
+ removeProjects.add(project);
+ return;
+ }
+ }
+
+ delta.accept(new IResourceDeltaVisitor() {
+ public boolean visit(IResourceDelta delta) {
+ IResource resource = delta.getResource();
+ if(resource instanceof IFile && IMavenConstants.POM_FILE_NAME.equals(resource.getName())) {
+ // XXX ignore output folders
+ if(delta.getKind() == IResourceDelta.REMOVED
+ || delta.getKind() == IResourceDelta.ADDED
+ || (delta.getKind() == IResourceDelta.CHANGED && ((delta.getFlags() & DELTA_FLAGS) != 0)))
+ {
+ // XXX check for interesting resources
+ refreshProjects.add(project);
+ }
+ }
+ return true;
+ }
+ });
+ }
+
+ private void queue(MavenUpdateRequest command) {
+ synchronized(queue) {
+ queue.add(command);
+ }
+ }
+
+ public void preferenceChange(PreferenceChangeEvent event) {
+ boolean offline = mavenConfiguration.isOffline();
+ boolean updateSnapshots = false;
+
+ if (event.getSource() instanceof IProject) {
+ queue(new MavenUpdateRequest(new IProject[] {(IProject) event.getSource()}, offline, updateSnapshots));
+ }
+ }
+
+ public boolean isEmpty() {
+ synchronized(queue) {
+ return queue.isEmpty();
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/RequiredCapability.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/RequiredCapability.java
new file mode 100644
index 00000000..0adf2681
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/RequiredCapability.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.io.Serializable;
+
+
+/**
+ * RequiredCapability
+ *
+ * @author igor
+ */
+public abstract class RequiredCapability implements Serializable {
+
+ private static final long serialVersionUID = -5445156687502685383L;
+
+ private final VersionlessKey versionlessKey;
+
+ public RequiredCapability(String namepsace, String id) {
+ if(namepsace == null || id == null) {
+ throw new NullPointerException();
+ }
+ this.versionlessKey = new VersionlessKey(namepsace, id);
+ }
+
+ public VersionlessKey getVersionlessKey() {
+ return versionlessKey;
+ }
+
+ /**
+ * Returns true if provided capability *potentially* satisfies this requirement. Capability/requirement match will be
+ * used to check if workspace project changes (new/changed/remove projects and metadata changes) affect other
+ * projects. isPotentialMatch Implementations should be good enough to avoid obviously pointless project dependency
+ * refreshes, but does not have to be perfectly precise.
+ */
+ public abstract boolean isPotentialMatch(Capability capability);
+
+ protected static <T> boolean eq(T a, T b) {
+ return a != null ? a.equals(b) : b == null;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/StaleMutableProjectRegistryException.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/StaleMutableProjectRegistryException.java
new file mode 100644
index 00000000..43f8ecd9
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/StaleMutableProjectRegistryException.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+/**
+ * StaleMutableProjectRegistryException
+ *
+ * @author igor
+ */
+public class StaleMutableProjectRegistryException extends IllegalStateException {
+
+ private static final long serialVersionUID = -1456658363775761949L;
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/VersionlessKey.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/VersionlessKey.java
new file mode 100644
index 00000000..55cef303
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/VersionlessKey.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.project.registry;
+
+import java.io.Serializable;
+
+
+/**
+ * VersionlessKey
+ *
+ * @author igor
+ */
+public class VersionlessKey implements Serializable {
+ private static final long serialVersionUID = 2125977578206347429L;
+
+ private final String namespace;
+
+ private final String id;
+
+ public VersionlessKey(String namespace, String id) {
+ if(namespace == null || id == null) {
+ throw new NullPointerException();
+ }
+ this.namespace = namespace;
+ this.id = id;
+ }
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public int hashCode() {
+ int hash = namespace.hashCode();
+ hash = hash * 17 + id.hashCode();
+ return hash;
+ }
+
+ public boolean equals(Object obj) {
+ if(obj == this) {
+ return true;
+ }
+ if(!(obj instanceof VersionlessKey)) {
+ return false;
+ }
+ VersionlessKey other = (VersionlessKey) obj;
+ return namespace.equals(other.namespace) && id.equals(other.id);
+ }
+
+ public String toString() {
+ return namespace + "/" + id; //$NON-NLS-1$
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/IRepositoryDiscoverer.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/IRepositoryDiscoverer.java
new file mode 100644
index 00000000..4dfbb56d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/IRepositoryDiscoverer.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.repository;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * IRepositoryDiscoverer
+ *
+ * @author igor
+ */
+public interface IRepositoryDiscoverer {
+
+ /**
+ * Called during updateRegistry operation.
+ */
+ public void addRepositories(RepositoryRegistry registry, IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/IRepositoryIndexer.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/IRepositoryIndexer.java
new file mode 100644
index 00000000..1573b657
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/IRepositoryIndexer.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.repository;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.m2e.core.repository.IRepository;
+
+/**
+ * IRepositoryIndexer
+ *
+ * @author igor
+ */
+public interface IRepositoryIndexer {
+
+ public String getIndexerId();
+
+ /**
+ * This method is called from a background thread which does not keep any workspace locks.
+ */
+ public void initialize(IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Called by repository registry when new repository is added.
+ *
+ * This method is called from a background thread which does not keep any workspace locks.
+ */
+ public void repositoryAdded(IRepository repository, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Called by repository registry when a repository is removed.
+ *
+ * This method is called from a background thread which does not keep any workspace locks.
+ */
+ public void repositoryRemoved(IRepository repository, IProgressMonitor monitor) throws CoreException;
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryInfo.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryInfo.java
new file mode 100644
index 00000000..a84aac55
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryInfo.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.repository;
+
+import java.io.File;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IPath;
+
+import org.apache.maven.artifact.repository.MavenArtifactRepository;
+import org.apache.maven.wagon.authentication.AuthenticationInfo;
+
+import org.eclipse.m2e.core.repository.IRepository;
+import org.eclipse.m2e.core.repository.IRepositoryRegistry;
+
+public class RepositoryInfo implements IRepository {
+
+ private final String id;
+ private final String repositoryUrl;
+ private final File basedir;
+ private final int scope;
+ private final AuthenticationInfo authInfo;
+
+ private String uid;
+
+ private String mirrorId;
+ private String mirrorOf;
+ private Set<IPath> projects = new HashSet<IPath>();
+
+ public RepositoryInfo(String id, String repositoryUrl, int scope, AuthenticationInfo authInfo) {
+ this(id, repositoryUrl, getBasedir(repositoryUrl), scope, authInfo);
+ }
+
+ public RepositoryInfo(String id, String repositoryUrl, File basedir, int scope, AuthenticationInfo authInfo) {
+ this.id = id;
+ this.repositoryUrl = repositoryUrl;
+ this.scope = scope;
+ this.authInfo = authInfo;
+ this.basedir = basedir;
+ }
+
+ public AuthenticationInfo getAuthenticationInfo() {
+ return authInfo;
+ }
+
+ public String getUrl() {
+ return repositoryUrl;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getMirrorId() {
+ return mirrorId;
+ }
+
+ public String getMirrorOf() {
+ return mirrorOf;
+ }
+
+ public void setMirrorOf(String mirrorOf) {
+ this.mirrorOf = mirrorOf;
+ }
+
+ public void setMirrorId(String mirrorId) {
+ this.mirrorId = mirrorId;
+ }
+
+ public Set<IPath> getProjects() {
+ return projects;
+ }
+
+ public void addProject(IPath project) {
+ if (isScope(IRepositoryRegistry.SCOPE_PROJECT)) {
+ projects.add(project);
+ }
+ }
+
+ public void removeProject(IPath project) {
+ projects.remove(project);
+ }
+
+ public String getUid() {
+ if (uid == null) {
+ uid = getUid(id, repositoryUrl, authInfo != null? authInfo.getUserName(): null);
+ }
+
+ return uid;
+ }
+
+ public static String getUid(String id, String repositoryUrl, String username) {
+ StringBuilder sb = new StringBuilder();
+ if (id != null) {
+ sb.append(id);
+ }
+ sb.append('|').append(repositoryUrl);
+ if (username != null) {
+ sb.append('|').append(username);
+ }
+ String uid;
+ try {
+ MessageDigest digest = MessageDigest.getInstance("MD5"); //$NON-NLS-1$
+ digest.update(sb.toString().getBytes());
+ byte messageDigest[] = digest.digest();
+ StringBuffer hexString = new StringBuffer();
+ for(int i = 0; i < messageDigest.length; i++ ) {
+ String hex = Integer.toHexString(0xFF & messageDigest[i]);
+ if(hex.length() == 1) {
+ hexString.append('0');
+ }
+ hexString.append(hex);
+ }
+ uid = hexString.toString();
+ } catch(NoSuchAlgorithmException ex) {
+ //this shouldn't happen with MD5
+ uid = sb.toString();
+ uid = uid.replace(':', '_').replace('/', '_').replace('|','_');
+ }
+ return uid;
+ }
+
+ public String getProtocol() {
+ return getProtocol(repositoryUrl);
+ }
+
+ // copy&paste from MavenArtifactRepository#protocol
+ public static String getProtocol(String repositoryUrl) {
+ final int pos = repositoryUrl.indexOf(":"); //$NON-NLS-1$
+
+ if(pos == -1) {
+ return "file"; //$NON-NLS-1$
+ }
+ return repositoryUrl.substring(0, pos).trim();
+ }
+
+ public static File getBasedir(String repositoryUrl) {
+ if (getProtocol(repositoryUrl).equalsIgnoreCase("file")) { //$NON-NLS-1$
+ // dirty trick!
+ MavenArtifactRepository trick = new MavenArtifactRepository();
+ trick.setUrl(repositoryUrl);
+ return new File(trick.getBasedir());
+ }
+ return null;
+ }
+
+ public File getBasedir() {
+ return basedir;
+ }
+
+ public boolean isScope(int scope) {
+ return (this.scope & scope) != 0;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (id != null) {
+ sb.append(id).append('|');
+ }
+ sb.append(repositoryUrl);
+ return sb.toString();
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryRegistry.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryRegistry.java
new file mode 100644
index 00000000..03179291
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryRegistry.java
@@ -0,0 +1,323 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.repository;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.settings.Mirror;
+import org.apache.maven.settings.Server;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.wagon.authentication.AuthenticationInfo;
+
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactRepositoryRef;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.embedder.ISettingsChangeListener;
+import org.eclipse.m2e.core.project.IMavenProjectChangedListener;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectChangedEvent;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.repository.IRepository;
+import org.eclipse.m2e.core.repository.IRepositoryRegistry;
+
+
+/**
+ * RepositoryRegistry
+ *
+ * @author igor
+ */
+public class RepositoryRegistry implements IRepositoryRegistry, IMavenProjectChangedListener, ISettingsChangeListener {
+
+ private final IMaven maven;
+
+ private final MavenProjectManager projectManager;
+
+ /**
+ * Maps repositoryUrl to IndexInfo of repository index
+ */
+ private final Map<String, RepositoryInfo> repositories = new ConcurrentHashMap<String, RepositoryInfo>();
+
+ /**
+ * Lazy instantiated local repository instance.
+ */
+ private RepositoryInfo localRepository;
+
+ /**
+ * Lock guarding lazy instantiation of localRepository instance
+ */
+ private final Object localRepositoryLock = new Object();
+
+ private final RepositoryInfo workspaceRepository;
+
+ private ArrayList<IRepositoryIndexer> indexers = new ArrayList<IRepositoryIndexer>();
+
+ private ArrayList<IRepositoryDiscoverer> discoverers = new ArrayList<IRepositoryDiscoverer>();
+
+ private final RepositoryRegistryUpdateJob job = new RepositoryRegistryUpdateJob(this);
+
+ public RepositoryRegistry(IMaven maven, MavenProjectManager projectManager) {
+ this.maven = maven;
+ this.projectManager = projectManager;
+
+ this.workspaceRepository = new RepositoryInfo(null/*id*/, "workspace://"/*url*/, null/*basedir*/, SCOPE_WORKSPACE, null/*auth*/); //$NON-NLS-1$
+ }
+
+ private RepositoryInfo newLocalRepositoryInfo() {
+ File localBasedir = new File(maven.getLocalRepositoryPath());
+ try {
+ localBasedir = localBasedir.getCanonicalFile();
+ } catch (IOException e) {
+ // will never happen
+ localBasedir = localBasedir.getAbsoluteFile();
+ }
+
+ String localUrl;
+ try {
+ localUrl = localBasedir.toURL().toExternalForm();
+ } catch(MalformedURLException ex) {
+ MavenLogger.log("Could not parse local repository path", ex);
+ localUrl = "file://" + localBasedir.getAbsolutePath(); //$NON-NLS-1$
+ }
+
+ // initialize local and workspace repositories
+ RepositoryInfo localRepository = new RepositoryInfo(null/*id*/, localUrl, localBasedir, SCOPE_LOCAL, null/*auth*/);
+ return localRepository;
+ }
+
+ public void mavenProjectChanged(MavenProjectChangedEvent[] events, IProgressMonitor monitor) {
+ /*
+ * This method is called while holding workspace lock. Avoid long-running operations if possible.
+ */
+
+ Settings settings = null;
+ try {
+ settings = maven.getSettings();
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+
+ for(MavenProjectChangedEvent event : events) {
+ IMavenProjectFacade oldFacade = event.getOldMavenProject();
+ if (oldFacade != null) {
+ removeProjectRepositories(oldFacade, monitor);
+ }
+ IMavenProjectFacade facade = event.getMavenProject();
+ if(facade != null) {
+ try {
+ addProjectRepositories(settings, facade, null /*asyncUpdate*/);
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+
+ private void addProjectRepositories(Settings settings, IMavenProjectFacade facade, IProgressMonitor monitor) throws CoreException {
+ ArrayList<ArtifactRepositoryRef> repositories = getProjectRepositories(facade);
+
+ for (ArtifactRepositoryRef repo : repositories) {
+ RepositoryInfo repository = getRepository(repo);
+ if (repository != null) {
+ repository.addProject(facade.getPom().getFullPath());
+ continue;
+ }
+ AuthenticationInfo auth = getAuthenticationInfo(settings, repo.getId());
+ repository = new RepositoryInfo(repo.getId(), repo.getUrl(), SCOPE_PROJECT, auth);
+ repository.addProject(facade.getPom().getFullPath());
+
+ addRepository(repository, monitor);
+ }
+ }
+
+ public void addRepository(RepositoryInfo repository, IProgressMonitor monitor) {
+ if (!repositories.containsKey(repository.getUid())) {
+ repositories.put(repository.getUid(), repository);
+
+ for (IRepositoryIndexer indexer : indexers) {
+ try {
+ indexer.repositoryAdded(repository, monitor);
+ } catch (CoreException e) {
+ MavenLogger.log(e);
+ }
+ }
+ }
+ }
+
+ private void removeProjectRepositories(IMavenProjectFacade facade, IProgressMonitor monitor) {
+ ArrayList<ArtifactRepositoryRef> repositories = getProjectRepositories(facade);
+
+ for (ArtifactRepositoryRef repo : repositories) {
+ RepositoryInfo repository = getRepository(repo);
+ if (repository != null && repository.isScope(SCOPE_PROJECT)) {
+ repository.removeProject(facade.getPom().getFullPath());
+ if (repository.getProjects().isEmpty()) {
+ removeRepository(repository, monitor);
+ }
+ }
+ }
+ }
+
+ private void removeRepository(RepositoryInfo repository, IProgressMonitor monitor) {
+ repositories.remove(repository.getUid());
+
+ for (IRepositoryIndexer indexer : indexers) {
+ try {
+ indexer.repositoryRemoved(repository, monitor);
+ } catch (CoreException e) {
+ MavenLogger.log(e);
+ }
+ }
+ }
+
+ private ArrayList<ArtifactRepositoryRef> getProjectRepositories(IMavenProjectFacade facade) {
+ ArrayList<ArtifactRepositoryRef> repositories = new ArrayList<ArtifactRepositoryRef>();
+ repositories.addAll(facade.getArtifactRepositoryRefs());
+ repositories.addAll(facade.getPluginArtifactRepositoryRefs());
+ return repositories;
+ }
+
+
+ public AuthenticationInfo getAuthenticationInfo(Settings settings, String id) throws CoreException {
+ if (settings == null) {
+ return null;
+ }
+
+ Server server = settings.getServer(id);
+ if (server == null || server.getUsername() == null) {
+ return null;
+ }
+
+ server = maven.decryptPassword(server);
+
+ AuthenticationInfo info = new AuthenticationInfo();
+ info.setUserName(server.getUsername());
+ info.setPassword(server.getPassword());
+ return info;
+ }
+
+ public void updateRegistry(IProgressMonitor monitor) throws CoreException {
+ Settings settings = maven.getSettings();
+ List<Mirror> mirrors = maven.getMirrors();
+
+ // initialize indexers
+ for (IRepositoryIndexer indexer : indexers) {
+ indexer.initialize(monitor);
+ }
+
+ // process configured repositories
+
+ Map<String, RepositoryInfo> oldRepositories = new HashMap<String, RepositoryInfo>(repositories);
+ repositories.clear();
+
+ addRepository(this.workspaceRepository, monitor);
+
+ synchronized(localRepositoryLock) {
+ this.localRepository = newLocalRepositoryInfo();
+ }
+ addRepository(this.localRepository, monitor);
+
+ // mirrors
+ for(Mirror mirror : mirrors) {
+ AuthenticationInfo auth = getAuthenticationInfo(settings, mirror.getId());
+ RepositoryInfo repository = new RepositoryInfo(mirror.getId(), mirror.getUrl(), SCOPE_SETTINGS, auth);
+ repository.setMirrorOf(mirror.getMirrorOf());
+ addRepository(repository, monitor);
+ }
+
+ // repositories from settings.xml
+ ArrayList<ArtifactRepository> repos = new ArrayList<ArtifactRepository>();
+ repos.addAll(maven.getArtifactRepositories(false));
+ repos.addAll(maven.getPluginArtifactRepositories(false));
+
+ for(ArtifactRepository repo : repos) {
+ Mirror mirror = maven.getMirror(repo);
+ AuthenticationInfo auth = getAuthenticationInfo(settings, repo.getId());
+ RepositoryInfo repository = new RepositoryInfo(repo.getId(), repo.getUrl(), SCOPE_SETTINGS, auth);
+ if (mirror != null) {
+ repository.setMirrorId(mirror.getId());
+ }
+ addRepository(repository, monitor);
+ }
+
+ // project-specific repositories
+ for (IMavenProjectFacade facade : projectManager.getProjects()) {
+ addProjectRepositories(settings, facade, monitor);
+ }
+
+ // custom repositories
+ for (IRepositoryDiscoverer discoverer : discoverers) {
+ discoverer.addRepositories(this, monitor);
+ }
+
+ oldRepositories.keySet().removeAll(repositories.keySet());
+ for (RepositoryInfo repository : oldRepositories.values()) {
+ removeRepository(repository, monitor);
+ }
+ }
+
+ public List<IRepository> getRepositories(int scope) {
+ ArrayList<IRepository> result = new ArrayList<IRepository>();
+ for (RepositoryInfo repository : repositories.values()) {
+ if (repository.isScope(scope)) {
+ result.add(repository);
+ }
+ }
+ return result;
+ }
+
+ public void updateRegistry() {
+ job.updateRegistry();
+ }
+
+ public void addRepositoryIndexer(IRepositoryIndexer indexer) {
+ this.indexers.add(indexer);
+ }
+
+ public void addRepositoryDiscoverer(IRepositoryDiscoverer discoverer) {
+ this.discoverers.add(discoverer);
+ }
+
+ public RepositoryInfo getRepository(ArtifactRepositoryRef ref) {
+ String uid = RepositoryInfo.getUid(ref.getId(), ref.getUrl(), ref.getUsername());
+ return repositories.get(uid);
+ }
+
+ public IRepository getWorkspaceRepository() {
+ return workspaceRepository;
+ }
+
+ public IRepository getLocalRepository() {
+ synchronized(localRepositoryLock) {
+ if(localRepository == null) {
+ localRepository = newLocalRepositoryInfo();
+ }
+ }
+
+ return localRepository;
+ }
+
+ public void settingsChanged(Settings settings) {
+ updateRegistry();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryRegistryUpdateJob.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryRegistryUpdateJob.java
new file mode 100644
index 00000000..9cf09960
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/repository/RepositoryRegistryUpdateJob.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.repository;
+
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.jobs.IBackgroundProcessingQueue;
+
+/**
+ * RepositoryRegistryUpdateJob
+ *
+ * @author igor
+ */
+public class RepositoryRegistryUpdateJob extends Job implements IBackgroundProcessingQueue {
+
+ private final RepositoryRegistry registry;
+
+ private final ArrayList<Object> queue = new ArrayList<Object>();
+
+ public RepositoryRegistryUpdateJob(RepositoryRegistry registry) {
+ super(Messages.RepositoryRegistryUpdateJob_title);
+ this.registry = registry;
+ }
+
+ public IStatus run(IProgressMonitor monitor) {
+ synchronized(queue) {
+ queue.clear();
+ }
+ try {
+ registry.updateRegistry(monitor);
+ } catch(CoreException ex) {
+ return ex.getStatus();
+ }
+ return Status.OK_STATUS;
+ }
+
+ public boolean isEmpty() {
+ synchronized(queue) {
+ return queue.isEmpty();
+ }
+ }
+
+ public void updateRegistry() {
+ synchronized(queue) {
+ queue.add(new Object());
+ schedule(1000L);
+ }
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/jobs/IBackgroundProcessingQueue.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/jobs/IBackgroundProcessingQueue.java
new file mode 100644
index 00000000..bc9e3986
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/jobs/IBackgroundProcessingQueue.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.jobs;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+
+/**
+ * Common interface implemented by all m2e background processing jobs.
+ *
+ * @author igor
+ */
+public interface IBackgroundProcessingQueue {
+ public void join() throws InterruptedException;
+
+ public boolean isEmpty();
+
+ public IStatus run(IProgressMonitor monitor);
+
+ public boolean cancel();
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/messages.properties b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/messages.properties
new file mode 100644
index 00000000..14080ec8
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/messages.properties
@@ -0,0 +1,152 @@
+#
+# Copyright (c) 2007, 2008 Sonatype, Inc.
+# 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
+#
+
+action.moduleProjectWizardAction=New Maven Module Project
+artifactComponent.artifact=Artifact
+artifactComponent.artifactId=Artifact Id\:
+artifactComponent.description=Description\:
+artifactComponent.groupId=Group Id\:
+artifactComponent.name=Name\:
+artifactComponent.package=Package\:
+artifactComponent.packaging=Packaging\:
+artifactComponent.version=Version\:
+directoriesComponent.projectLayout=Project layout
+launch.browseFs=Browse File Syste&m...
+launch.browseVariables=&Variables...
+launch.browseWorkspace=Browse &Workspace...
+launch.choosePomDir=Choose &Base directory
+launch.errorPomMissing=Base directory doesn't exist
+launch.errorSelectPom=Please select Base directory first
+launch.goals=&Select...
+launch.goalsDialog.lifecycleBuild=Build Lifecycle Phases
+launch.goalsDialog.lifecycleClean=Clean Lifecycle Phases
+launch.goalsDialog.lifecycleSite=Site Lifecycle Phases
+launch.goalsDialog.title=Goals
+launch.goalsLabel=&Goals\:
+launch.mainTabName=Main
+launch.pomDirectoryDoesntExist=Base directory doesn't exist or can't be read
+launch.pomDirectoryEmpty=Base directory should be specified
+launch.pomGroup=Base directory:
+launch.profilesLabel=&Profiles\:
+launch.propAddButton=&Add...
+launch.propName=Parameter Name
+launch.propRemoveButton=&Remove
+launch.propEditButton=E&dit...
+launch.propValue=Value
+launch.propertyDialog.browseVariables=Varia&bles...
+launch.propertyDialog.name=Name\:
+launch.propertyDialog.value=Value\:
+locationComponent.atExternal=Create project at e&xternal location
+locationComponent.browse=B&rowse...
+locationComponent.directory=&Location\:
+locationComponent.inWorkspace=Create project in &workspace
+locationComponent.location=Location
+locationComponent.selectLocation=Select Location
+plugin.markerArtifactResolutionError=Artifact resolution error\:
+plugin.markerBuildError=Project build error\: {0}
+plugin.markerParsingError=Parsing error\:
+preferences.checksumPolicyFail=fail
+preferences.checksumPolicyIgnore=ignore
+preferences.checksumPolicyWarn=warning
+preferences.debugOutput=Debu&g Output
+preferences.downloadSources=Do&wnload Artifact Sources
+preferences.downloadJavadoc=Download Artifact &JavaDoc
+preferences.globalChecksumPolicy=Global Checksum &Policy\:
+preferences.globalSettingsFile=&Global Settings File\:
+preferences.goalOnImport=Goals to run on project i&mport\:
+preferences.goalOnUpdate=Goals to run when &updating project configuration\:
+preferences.localRepository=Local Repository\:
+preferences.offline=&Offline
+preferences.refreshButton=Re&fresh Settings
+preferences.reindexButton=Re&index
+preferences.userSettingsFile=User Settings File\:
+projectSelectionDialog.title=Select a Maven project
+resolverConfiguration.advanced=Ad&vanced
+resolverConfiguration.enableResourceFiltering=Enable &resource filtering
+resolverConfiguration.profiles=&Profiles\:
+resolverConfiguration.projectsForModules=&Separate projects for modules
+resolverConfiguration.resolveWorkspaceProjects=Resolve &Workspace projects
+resolverConfiguration.template=Name &template\:
+resolverConfiguration.templateDescription=Optional Eclipse project name template, e.g. "[groupId].[artifactId]-[version]"
+resolverConfiguration.useMavenOutputFolders=Use Maven &output folders
+wizard.import.page.browse=&Browse...
+wizard.import.page.deselectAll=&Deselect All
+wizard.import.page.projects=&Projects\:
+wizard.import.page.refresh=&Refresh
+wizard.import.page.root=&Root Directory\:
+wizard.import.page.scanningErrors=Scanning errors ({0})\:
+wizard.import.page.selectAll=Select &All
+wizard.import.page.selectRootFolder=Select Root Folder
+wizard.import.validator.projectExists=Project {0} already exists\n Add a version or custom suffix using "Name template" in "Advanced" settings
+wizard.import.validator.workspaceFolder=Can't import project {0} from an existing workspace folder
+wizard.module.page.archetype.title=New Maven Module
+wizard.module.page.artifact.title=New Maven Module
+wizard.module.page.parameters.title=New Maven Module
+wizard.module.page.parent.browse=Br&owse...
+wizard.module.page.parent.description=Select the module name and parent
+wizard.module.page.parent.moduleName=&Module Name\:
+wizard.module.page.parent.parentProject=Parent Project\:
+wizard.module.page.parent.title=New Maven Module
+wizard.module.page.parent.validator.moduleName=Enter a module name.
+wizard.module.page.parent.validator.nameExists=A resource with this name already exists.
+wizard.module.page.parent.validator.parentProject=Select a parent project.
+wizard.module.page.title=New Maven module
+wizard.module.title=New Maven Module
+wizard.project.error.pomAlreadyExists=A pom.xml file already exists in the destination folder.
+wizard.project.error.pomExists=POM already exists
+wizard.project.job.creating=Creating {0}
+wizard.project.job.creatingProject=Creating project "{0}"
+wizard.project.job.failed=Failed to create project "{0}"
+wizard.project.page.archetype.archetypes=Archetypes\:
+wizard.project.page.archetype.column.artifactId=Artifact Id
+wizard.project.page.archetype.column.groupId=Group Id
+wizard.project.page.archetype.column.version=Version
+wizard.project.page.archetype.description=Select an Archetype
+wizard.project.page.archetype.details=Archetype Details
+wizard.project.page.archetype.details.description=Description\:
+wizard.project.page.archetype.details.repository=Repository\:
+wizard.project.page.archetype.retrievingArchetypes=Retrieving archetypes\:
+wizard.project.page.archetype.title=New Maven project
+wizard.project.page.artifact.parent.artifactId=Artifact Id\:
+wizard.project.page.artifact.parent.browse=Browse...
+wizard.project.page.artifact.parent.clear=Clear
+wizard.project.page.artifact.parent.groupId=Group Id\:
+wizard.project.page.artifact.parent.title=Parent Project
+wizard.project.page.artifact.parent.version=Version\:
+wizard.project.page.dependencies.add=&Add...
+wizard.project.page.dependencies.dependencies=Maven dependencies\:
+wizard.project.page.dependencies.description=Add additional dependencies to the project.
+wizard.project.page.dependencies.remove=&Remove
+wizard.project.page.dependencies.title=Select additional dependencies
+wizard.project.page.maven2.archetype.parameters.description=Specify Archetype parameters
+wizard.project.page.maven2.description=Configure project
+wizard.project.page.maven2.title=New Maven project
+wizard.project.page.maven2.validator.artifactID=Enter an artifact id.
+wizard.project.page.maven2.validator.artifactIDnospaces=Artifact id cannot contain spaces.
+wizard.project.page.maven2.validator.artifactIDinvalid=Invalid artifact id: {0}
+wizard.project.page.maven2.validator.groupID=Enter a group id for the artifact.
+wizard.project.page.maven2.validator.groupIDnospaces=Group id cannot contain spaces.
+wizard.project.page.maven2.validator.groupIDinvalid=Invalid group id: {0}
+wizard.project.page.maven2.validator.projectNameInvalid=Invalid project name: {0}
+wizard.project.page.maven2.validator.packaging=Enter a packaging for the artifact.
+wizard.project.page.maven2.validator.parent=To specify a parent project, set the parent group id, artifact id and version.
+wizard.project.page.maven2.validator.requiredProperty=Required property "{0}" is not set.
+wizard.project.page.maven2.validator.version=Enter a version for the artifact.
+wizard.project.page.project.description=Select project name and location
+wizard.project.page.project.projectName=&Project name\:
+wizard.project.page.project.simpleProject=Create a &simple project (skip archetype selection)
+wizard.project.page.project.title=New Maven project
+wizard.project.page.project.validator.invalidLocation=Invalid project location path
+wizard.project.page.project.validator.projectExists=Project "{0}" already exists.
+wizard.project.page.project.validator.projectLocation=Enter a location for the project.
+wizard.project.page.project.validator.projectName=Enter a project name.
+wizard.project.title=New Maven Project
+jira.username=Jira username (will use default user if empty)
+jira.password=Jira password
+pomEditor.defaultPage=Open XML page in the POM editor by default
+pomEditor.showAdvancedTabs=Show advanced tabs in the POM editor \ No newline at end of file
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/AbstractProjectScanner.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/AbstractProjectScanner.java
new file mode 100644
index 00000000..c996a869
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/AbstractProjectScanner.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+
+/**
+ * Project Scanner
+ *
+ * @author Eugene Kuleshov
+ */
+public abstract class AbstractProjectScanner<T extends MavenProjectInfo> {
+
+ private final List<T> projects = new ArrayList<T>();
+ private final List<Throwable> errors = new ArrayList<Throwable>();
+
+ /**
+ * Returns <code>List</code> of {@link MavenProjectInfo}
+ */
+ public List<T> getProjects() {
+ return projects;
+ }
+
+ /**
+ * Returns <code>List</code> of <code>Exception</code>
+ */
+ public List<Throwable> getErrors() {
+ return this.errors;
+ }
+
+ protected void addProject(T mavenProjectInfo) {
+ projects.add(mavenProjectInfo);
+ }
+
+ protected void addError(Throwable exception) {
+ errors.add(exception);
+ }
+
+ public abstract String getDescription();
+
+ public abstract void run(IProgressMonitor monitor) throws InterruptedException;
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenMarkerManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenMarkerManager.java
new file mode 100644
index 00000000..a96622ba
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenMarkerManager.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+
+import org.apache.maven.execution.MavenExecutionResult;
+
+/**
+ * IMavenMarkerManager
+ *
+ * @author Fred Bricon
+ */
+public interface IMavenMarkerManager {
+
+ /**
+ * Add markers to a pom file from a MavenExecutionResult.
+ * @param pomFile the pom file to attach markers to.
+ * @param result containing messages to be addedd as markers
+ */
+ public void addMarkers(IResource pomFile, String type, MavenExecutionResult result);
+
+ /**
+ * Add a Maven marker to a resource
+ * @param resource : the IResource to attach the marker to.
+ * @param message : the marker's message.
+ * @param lineNumber : the resource line to attach the marker to.
+ * @param severity : the severity of the marker.
+ */
+ public IMarker addMarker(IResource resource, String type, String message, int lineNumber, int severity);
+
+ /**
+ * Delete all Maven markers of the specified type from an IResource
+ */
+ public void deleteMarkers(IResource resource, String type) throws CoreException;
+
+ /**
+ * Transform an exception into an error marker on an IResource
+ */
+ public void addErrorMarkers(IResource resource, String type, Exception ex);
+
+ public void addEditorHintMarkers(IResource pom, String type);
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectChangedListener.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectChangedListener.java
new file mode 100644
index 00000000..f37ec18d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectChangedListener.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public interface IMavenProjectChangedListener {
+ /**
+ * This method is called while holding workspace lock.
+ */
+ public void mavenProjectChanged(MavenProjectChangedEvent[] events, IProgressMonitor monitor);
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectFacade.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectFacade.java
new file mode 100644
index 00000000..ded501aa
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectFacade.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.ArtifactRef;
+import org.eclipse.m2e.core.embedder.ArtifactRepositoryRef;
+import org.eclipse.m2e.core.internal.project.ProjectConfigurationManager;
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+
+/**
+ * IMavenProjectFacade
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ *
+ * @author Igor Fedorenko
+ */
+public interface IMavenProjectFacade {
+
+ /**
+ * Returns project relative paths of resource directories
+ */
+ IPath[] getResourceLocations();
+
+ /**
+ * Returns project relative paths of test resource directories
+ */
+ IPath[] getTestResourceLocations();
+
+ IPath[] getCompileSourceLocations();
+
+ IPath[] getTestCompileSourceLocations();
+
+ /**
+ * Returns project resource for given file system location or null the location is outside of project.
+ *
+ * @param resourceLocation absolute file system location
+ * @return IPath the full, absolute workspace path resourceLocation
+ */
+ IPath getProjectRelativePath(String resourceLocation);
+
+ /**
+ * Returns the full, absolute path of this project maven build output directory relative to the workspace or null if
+ * maven build output directory cannot be determined or outside of the workspace.
+ */
+ IPath getOutputLocation();
+
+ /**
+ * Returns the full, absolute path of this project maven build test output directory relative to the workspace or null
+ * if maven build output directory cannot be determined or outside of the workspace.
+ */
+ IPath getTestOutputLocation();
+
+ IPath getFullPath();
+
+ /**
+ * Lazy load and cache MavenProject instance
+ */
+ MavenProject getMavenProject(IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Returns cached MavenProject instance associated with this facade or null,
+ * if the cache has not been populated yet.
+ */
+ MavenProject getMavenProject();
+
+ /**
+ * Lazy load and cache build execution plan
+ */
+ MavenExecutionPlan getExecutionPlan(IProgressMonitor monitor) throws CoreException;
+
+ String getPackaging();
+
+ IProject getProject();
+
+ IFile getPom();
+
+ File getPomFile();
+
+ /**
+ * Returns the full, absolute path of the given file relative to the workspace. Returns null if the file does not
+ * exist or is not a member of this project.
+ */
+ IPath getFullPath(File file);
+
+ /**
+ * Visits trough Maven project artifacts and modules
+ *
+ * @param visitor a project visitor used to visit Maven project
+ * @param flags flags to specify visiting behavior. See {@link IMavenProjectVisitor#LOAD},
+ * {@link IMavenProjectVisitor#NESTED_MODULES}.
+ */
+ void accept(IMavenProjectVisitor visitor, int flags) throws CoreException;
+
+ void accept(IMavenProjectVisitor2 visitor, int flags, IProgressMonitor monitor) throws CoreException;
+
+ List<String> getMavenProjectModules();
+
+ Set<ArtifactRef> getMavenProjectArtifacts();
+
+ ResolverConfiguration getResolverConfiguration();
+
+ /**
+ * @return true if maven project needs to be re-read from disk
+ */
+ boolean isStale();
+
+ ArtifactKey getArtifactKey();
+
+ /**
+ * Associates the value with the key in session (i.e. transient) context.
+ * Intended as a mechanism to cache state derived from MavenProject.
+ * Session properties are cleared when MavenProject is re-read from disk.
+ *
+ * @see #getSessionProperty(String)
+ */
+ public void setSessionProperty(String key, Object value);
+
+ /**
+ * @return the value associated with the key in session context or null
+ * if the key is not associated with any value.
+ *
+ * @see #setSessionProperty(String, Object)
+ */
+ public Object getSessionProperty(String key);
+
+ public Set<ArtifactRepositoryRef> getArtifactRepositoryRefs();
+
+ public Set<ArtifactRepositoryRef> getPluginArtifactRepositoryRefs();
+
+ public ILifecycleMapping getLifecycleMapping(IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Returns true if the project configuration is valid. This flag is set by
+ * {@link ProjectConfigurationManager#validateProjectConfiguration(IMavenProjectFacade, IProgressMonitor)}. Returns
+ * false if the project configuration has not been validated yet.
+ */
+ boolean hasValidConfiguration();
+
+ void setHasValidConfiguration(boolean hasValidConfiguration);
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectImportResult.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectImportResult.java
new file mode 100644
index 00000000..218e5a4d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectImportResult.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import org.eclipse.core.resources.IProject;
+
+/**
+ * Holds IProject that was created during project import
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IMavenProjectImportResult {
+
+ /**
+ * @return MavenProjectInfo maven project import request
+ */
+ MavenProjectInfo getMavenProjectInfo();
+
+ /**
+ * @return IProject imported project or <code>null</code> if the project could not be imported.
+ */
+ IProject getProject();
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectVisitor.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectVisitor.java
new file mode 100644
index 00000000..71a5e400
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectVisitor.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * This interface is implemented by clients that visit MavenProject tree.
+ */
+public interface IMavenProjectVisitor {
+
+ public static int NONE = 0;
+
+ public static int LOAD = 1 << 0;
+
+ /**
+ * Visit Maven project or project module
+ *
+ * @param projectFacade a facade for visited Maven project
+ * @return true if nested artifacts and modules should be visited
+ */
+ public boolean visit(IMavenProjectFacade projectFacade) throws CoreException;
+
+ /**
+ * Visit Maven project dependency/artifact
+ *
+ * @param projectFacade a facade for visited Maven project
+ * @param artifact an artifact for project dependency
+ */
+// public void visit(IMavenProjectFacade projectFacade, Artifact artifact);
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectVisitor2.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectVisitor2.java
new file mode 100644
index 00000000..5effc055
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IMavenProjectVisitor2.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import org.apache.maven.artifact.Artifact;
+
+/**
+ * IMavenProjectVisitor2
+ *
+ * @author Igor Fedorenko
+ */
+public interface IMavenProjectVisitor2 extends IMavenProjectVisitor {
+
+ /**
+ * @param mavenProjectFacade
+ * @param artifact
+ */
+ void visit(IMavenProjectFacade mavenProjectFacade, Artifact artifact);
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IProjectConfigurationManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IProjectConfigurationManager.java
new file mode 100644
index 00000000..a36aa966
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/IProjectConfigurationManager.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+
+import org.apache.maven.archetype.catalog.Archetype;
+import org.apache.maven.model.Model;
+
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+
+
+public interface IProjectConfigurationManager {
+
+ ISchedulingRule getRule();
+
+ List<IMavenProjectImportResult> importProjects(Collection<MavenProjectInfo> projects, //
+ ProjectImportConfiguration configuration, IProgressMonitor monitor) throws CoreException;
+
+ void createSimpleProject(IProject project, IPath location, Model model, String[] folders,
+ ProjectImportConfiguration configuration, IProgressMonitor monitor) throws CoreException;
+
+ void createArchetypeProject(IProject project, IPath location, Archetype archetype, //
+ String groupId, String artifactId, String version, String javaPackage, Properties properties, //
+ ProjectImportConfiguration configuration, IProgressMonitor monitor) throws CoreException;
+
+ Set<MavenProjectInfo> collectProjects(Collection<MavenProjectInfo> projects);
+
+ void enableMavenNature(IProject project, ResolverConfiguration configuration, IProgressMonitor monitor)
+ throws CoreException;
+
+ void disableMavenNature(IProject project, IProgressMonitor monitor) throws CoreException;
+
+ void updateProjectConfiguration(IProject project, ResolverConfiguration configuration, IProgressMonitor monitor)
+ throws CoreException;
+
+ ILifecycleMapping getLifecycleMapping(IMavenProjectFacade projectFacade, IProgressMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Validates that the project configuration is valid. It does not actually (re)configure the project, but it validates
+ * that the project configure action will not fail for obvious reasons like missing lifecycle mapping, missing project
+ * configuration, etc.
+ *
+ * @return true if the configuration is valid
+ */
+ boolean validateProjectConfiguration(IMavenProjectFacade projectFacade, IProgressMonitor monitor);
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/LocalProjectScanner.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/LocalProjectScanner.java
new file mode 100644
index 00000000..b397910e
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/LocalProjectScanner.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Profile;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.embedder.MavenModelManager;
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class LocalProjectScanner extends AbstractProjectScanner<MavenProjectInfo> {
+ private final File workspaceRoot;
+ private final List<String> folders;
+ private final boolean basedirRemameRequired;
+
+ private Set<File> scannedFolders = new HashSet<File>();
+ private final MavenConsole console;
+ private final MavenModelManager modelManager;
+
+ public LocalProjectScanner(File workspaceRoot, String folder, boolean needsRename, MavenModelManager modelManager,
+ MavenConsole console) {
+ this(workspaceRoot, Collections.singletonList(folder), needsRename, modelManager, console);
+ }
+
+ public LocalProjectScanner(File workspaceRoot, List<String> folders, boolean basedirRemameRequired,
+ MavenModelManager modelManager, MavenConsole console) {
+ this.workspaceRoot = workspaceRoot;
+ this.folders = folders;
+ this.basedirRemameRequired = basedirRemameRequired;
+ this.modelManager = modelManager;
+ this.console = console;
+ }
+
+ public void run(IProgressMonitor monitor) throws InterruptedException {
+ monitor.beginTask(Messages.LocalProjectScanner_task_scanning, IProgressMonitor.UNKNOWN);
+ try {
+ for(String folderName : folders) {
+ try {
+ File folder = new File(folderName).getCanonicalFile();
+ scanFolder(folder, new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN));
+ } catch(IOException ex) {
+ addError(ex);
+ }
+ }
+ } finally {
+ monitor.done();
+ }
+ }
+
+ private void scanFolder(File baseDir, IProgressMonitor monitor) throws InterruptedException {
+ if(monitor.isCanceled()) {
+ throw new InterruptedException();
+ }
+
+ monitor.subTask(baseDir.toString());
+ monitor.worked(1);
+
+ // Don't scan the .metadata folder
+ if(!baseDir.exists() || !baseDir.isDirectory() || IMavenConstants.METADATA_FOLDER.equals(baseDir.getName())) {
+ return;
+ }
+
+ MavenProjectInfo projectInfo = readMavenProjectInfo(baseDir, "", null); //$NON-NLS-1$
+ if(projectInfo != null) {
+ addProject(projectInfo);
+ return; // don't scan subfolders of the Maven project
+ }
+
+ File[] files = baseDir.listFiles();
+ for(int i = 0; i < files.length; i++ ) {
+ File file;
+ try {
+ file = files[i].getCanonicalFile();
+ if(file.isDirectory()) {
+ scanFolder(file, monitor);
+ }
+ } catch(IOException ex) {
+ addError(ex);
+ }
+ }
+ }
+
+ private MavenProjectInfo readMavenProjectInfo(File baseDir, String modulePath, MavenProjectInfo parentInfo) {
+ try {
+ baseDir = baseDir.getCanonicalFile();
+
+ File pomFile = new File(baseDir, IMavenConstants.POM_FILE_NAME);
+ if(!pomFile.exists()) {
+ return null;
+ }
+
+ Model model = modelManager.readMavenModel(pomFile);
+
+ if (!scannedFolders.add(baseDir)) {
+ return null; // we already know this project
+ }
+
+ String pomName = modulePath + "/" + IMavenConstants.POM_FILE_NAME; //$NON-NLS-1$
+
+ MavenProjectInfo projectInfo = newMavenProjectInfo(pomName, pomFile, model, parentInfo);
+ projectInfo.setBasedirRename(getBasedirRename(projectInfo));
+
+ Map<String, Set<String>> modules = new LinkedHashMap<String, Set<String>>();
+ for(String module : model.getModules()) {
+ modules.put(module, new HashSet<String>());
+ }
+
+ for(Profile profile : model.getProfiles()) {
+ for(String module : profile.getModules()) {
+ Set<String> profiles = modules.get(module);
+ if(profiles == null) {
+ profiles = new HashSet<String>();
+ modules.put(module, profiles);
+ }
+ profiles.add(profile.getId());
+ }
+ }
+
+ for(Map.Entry<String, Set<String>> e : modules.entrySet()) {
+ String module = e.getKey();
+ Set<String> profiles = e.getValue();
+
+ File moduleBaseDir = new File(baseDir, module);
+ MavenProjectInfo moduleInfo = readMavenProjectInfo(moduleBaseDir, module, projectInfo);
+ if(moduleInfo != null) {
+ moduleInfo.addProfiles(profiles);
+ projectInfo.add(moduleInfo);
+ }
+ }
+
+ return projectInfo;
+
+ } catch(CoreException ex) {
+ addError(ex);
+ console.logError("Unable to read model " + baseDir.getAbsolutePath());
+ } catch(IOException ex) {
+ addError(ex);
+ console.logError("Unable to read model " + baseDir.getAbsolutePath());
+ }
+
+ return null;
+ }
+
+ protected MavenProjectInfo newMavenProjectInfo(String label, File pomFile, Model model, MavenProjectInfo parent) {
+ return new MavenProjectInfo(label, pomFile, model, parent);
+ }
+
+ public String getDescription() {
+ return folders.toString();
+ }
+
+ private int getBasedirRename(MavenProjectInfo mavenProjectInfo) throws IOException {
+ File cannonical = mavenProjectInfo.getPomFile().getParentFile().getParentFile().getCanonicalFile();
+ if (basedirRemameRequired && cannonical.equals(workspaceRoot.getCanonicalFile())) {
+ return MavenProjectInfo.RENAME_REQUIRED;
+ }
+ return MavenProjectInfo.RENAME_NO;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectChangedEvent.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectChangedEvent.java
new file mode 100644
index 00000000..e0d775ef
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectChangedEvent.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import org.eclipse.core.resources.IFile;
+
+public class MavenProjectChangedEvent {
+
+ private final IFile source;
+
+ private final int kind;
+
+ private final int flags;
+
+ public static final int KIND_ADDED = 1;
+
+ public static final int KIND_REMOVED = 2;
+
+ public static final int KIND_CHANGED = 3;
+
+ public static final int FLAG_NONE = 0;
+
+ public static final int FLAG_DEPENDENCIES = 1;
+
+ public static final int FLAG_DEPENDENCY_SOURCES = 2;
+
+ public static final int FLAG_ENTRY_SOURCES = 3;
+
+ private final IMavenProjectFacade oldMavenProject;
+
+ private final IMavenProjectFacade mavenProject;
+
+ public MavenProjectChangedEvent(IFile source, int kind, int flags, IMavenProjectFacade oldMavenProject, IMavenProjectFacade mavenProject) {
+ this.source = source;
+ this.kind = kind;
+ this.flags = flags;
+ this.oldMavenProject = oldMavenProject;
+ this.mavenProject = mavenProject;
+ }
+
+ public int getKind() {
+ return kind;
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
+ public IMavenProjectFacade getMavenProject() {
+ return mavenProject;
+ }
+
+ public IMavenProjectFacade getOldMavenProject() {
+ return oldMavenProject;
+ }
+
+ public IFile getSource() {
+ return source;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectInfo.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectInfo.java
new file mode 100644
index 00000000..64088a15
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectInfo.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.model.Model;
+
+import org.eclipse.m2e.core.core.MavenLogger;
+
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class MavenProjectInfo {
+
+ /**
+ * Project basedir must NOT be renamed on filesystem.
+ */
+ public static final int RENAME_NO = 0;
+
+ /**
+ * Project basedir MUST be ranamed to match workspace project name.
+ */
+ public static final int RENAME_REQUIRED = 2;
+
+ private final String label;
+
+ private File pomFile;
+
+ private Model model;
+
+ private final MavenProjectInfo parent;
+
+ /**
+ * Map of MavenProjectInfo
+ */
+ private final Map<String, MavenProjectInfo> projects = new LinkedHashMap<String, MavenProjectInfo>();
+
+ private final Set<String> profiles = new HashSet<String>();
+
+ private int basedirRename = RENAME_NO;
+
+ public MavenProjectInfo(String label, File pomFile, Model model, MavenProjectInfo parent) {
+ this.label = label;
+ this.pomFile = pomFile;
+ this.model = model;
+ this.parent = parent;
+ }
+
+ public void setPomFile(File pomFile) {
+ File oldDir = this.pomFile.getParentFile();
+ File newDir = pomFile.getParentFile();
+
+ for(MavenProjectInfo projectInfo : projects.values()) {
+ File childPom = projectInfo.getPomFile();
+ if(isSubDir(oldDir, childPom.getParentFile())) {
+ String oldPath = oldDir.getAbsolutePath();
+ String path = childPom.getAbsolutePath().substring(oldPath.length());
+ projectInfo.setPomFile(new File(newDir, path));
+ }
+ }
+
+ this.pomFile = pomFile;
+ }
+
+ /** @deprecated use set/get BasedirRename */
+ public void setNeedsRename(boolean needsRename) {
+ setBasedirRename(needsRename? RENAME_REQUIRED: RENAME_NO);
+ }
+
+ /** @deprecated use set/get BasedirRenamePolicy */
+ public boolean isNeedsRename() {
+ return getBasedirRename() == RENAME_REQUIRED;
+ }
+
+ /**
+ * See {@link #RENAME_NO}, {@link #RENAME_REQUIRED}
+ */
+ public void setBasedirRename(int basedirRename) {
+ this.basedirRename = basedirRename;
+ }
+
+ /**
+ * See {@link #RENAME_NO}, {@link #RENAME_REQUIRED}
+ */
+ public int getBasedirRename() {
+ return basedirRename;
+ }
+
+ private boolean isSubDir(File parentDir, File subDir) {
+ if(parentDir.equals(subDir)) {
+ return true;
+ }
+
+ if(subDir.getParentFile()!=null) {
+ return isSubDir(parentDir, subDir.getParentFile());
+ }
+
+ return false;
+ }
+
+ public void add(MavenProjectInfo info) {
+ String key;
+ try {
+ if(info.getPomFile() == null) {
+ // Is this possible?
+ key = info.getLabel();
+ } else {
+ key = info.getPomFile().getCanonicalPath();
+ }
+ } catch(IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ MavenProjectInfo i = projects.get(key);
+ if(i==null) {
+ projects.put(key, info);
+ } else {
+ MavenLogger.log("Project info " + this + " already has a child project info with key '" + key + "'"); //$NON-NLS-3$
+ for(Iterator<String> it = info.getProfiles().iterator(); it.hasNext();) {
+ i.addProfile(it.next());
+ }
+ }
+ }
+
+ public void addProfile(String profileId) {
+ if(profileId!=null) {
+ this.profiles.add(profileId);
+ }
+ }
+
+ public void addProfiles(Collection<String> profiles) {
+ this.profiles.addAll(profiles);
+ }
+
+ public String getLabel() {
+ return this.label;
+ }
+
+ public File getPomFile() {
+ return this.pomFile;
+ }
+
+ public Model getModel() {
+ return this.model;
+ }
+
+ public void setModel(Model model) {
+ this.model = model;
+ }
+
+ public Collection<MavenProjectInfo> getProjects() {
+ return this.projects.values();
+ }
+
+ public MavenProjectInfo getParent() {
+ return this.parent;
+ }
+
+ public Set<String> getProfiles() {
+ return this.profiles;
+ }
+
+ public boolean equals(Object obj) {
+ if(obj instanceof MavenProjectInfo) {
+ MavenProjectInfo info = (MavenProjectInfo) obj;
+ if(pomFile == null) {
+ return info.getPomFile() == null;
+ }
+ return pomFile.equals(info.getPomFile());
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return pomFile==null ? 0 : pomFile.hashCode();
+ }
+
+ public String toString() {
+ return "'" + label + "'" + (pomFile == null ? "" : " " + pomFile.getAbsolutePath()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectManager.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectManager.java
new file mode 100644
index 00000000..303d30a7
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectManager.java
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import java.io.File;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+import org.apache.maven.artifact.repository.MavenArtifactRepository;
+import org.apache.maven.execution.MavenExecutionRequest;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.internal.project.registry.ProjectRegistryManager;
+import org.eclipse.m2e.core.internal.project.registry.ProjectRegistryRefreshJob;
+
+
+/**
+ * This class keeps track of all Maven projects present in the workspace and provides mapping between Maven artifacts
+ * and Workspace projects.
+ */
+public class MavenProjectManager {
+
+ public static final String STATE_FILENAME = "workspacestate.properties"; //$NON-NLS-1$
+
+ private final ProjectRegistryManager manager;
+
+ private final ProjectRegistryRefreshJob mavenBackgroundJob;
+
+ private final File workspaceStateFile;
+
+ public MavenProjectManager(ProjectRegistryManager manager, ProjectRegistryRefreshJob mavenBackgroundJob, File stateLocation) {
+ this.manager = manager;
+ this.mavenBackgroundJob = mavenBackgroundJob;
+ this.workspaceStateFile = new File(stateLocation, STATE_FILENAME);
+ }
+
+ // Maven projects
+
+ /**
+ * Performs requested Maven project update asynchronously, using background
+ * job. This method returns immediately.
+ */
+ public void refresh(MavenUpdateRequest request) {
+ mavenBackgroundJob.refresh(request);
+ }
+
+ /**
+ * Performs requested Maven project update synchronously. In other words, this method
+ * does not return until all affected projects have been updated and
+ * corresponding MavenProjectChangeEvent's broadcast.
+ *
+ * This method acquires a lock on the workspace's root.
+ */
+ public void refresh(MavenUpdateRequest request, IProgressMonitor monitor) throws CoreException {
+ manager.refresh(request, monitor);
+ }
+
+ public void addMavenProjectChangedListener(IMavenProjectChangedListener listener) {
+ manager.addMavenProjectChangedListener(listener);
+ }
+
+ public void removeMavenProjectChangedListener(IMavenProjectChangedListener listener) {
+ manager.removeMavenProjectChangedListener(listener);
+ }
+
+ /**
+ * Returns MavenProjectFacade corresponding to the pom. This method first looks in the project cache, then attempts to
+ * load the pom if the pom is not found in the cache. In the latter case, workspace resolution is assumed to be
+ * enabled for the pom but the pom will not be added to the cache.
+ */
+ public IMavenProjectFacade create(IFile pom, boolean load, IProgressMonitor monitor) {
+ return manager.create(pom, load, monitor);
+ }
+
+ public IMavenProjectFacade create(IProject project, IProgressMonitor monitor) {
+ return manager.create(project, monitor);
+ }
+
+ public ResolverConfiguration getResolverConfiguration(IProject project) {
+ IMavenProjectFacade projectFacade = create(project, new NullProgressMonitor());
+ if(projectFacade!=null) {
+ return projectFacade.getResolverConfiguration();
+ }
+ return manager.readResolverConfiguration(project);
+ }
+
+ public boolean setResolverConfiguration(IProject project, ResolverConfiguration configuration) {
+ return manager.setResolverConfiguration(project, configuration);
+ }
+
+ /**
+ * @return MavenProjectFacade[] all maven projects which exist under workspace root
+ */
+ public IMavenProjectFacade[] getProjects() {
+ return manager.getProjects();
+ }
+
+ /**
+ * @return IMavenProjectFacade cached IMavenProjectFacade corresponding
+ * to the project or null if there is no cache entry for the project.
+ */
+ public IMavenProjectFacade getProject(IProject project) {
+ return manager.getProject(project);
+ }
+
+ public IMavenProjectFacade getMavenProject(String groupId, String artifactId, String version) {
+ return manager.getMavenProject(groupId, artifactId, version);
+ }
+
+ public File getWorkspaceStateFile() {
+ return workspaceStateFile;
+ }
+
+ /**
+ * Request full maven build for a project.
+ *
+ * This call only has effect for projects that have maven nature and
+ * Maven builder configured.
+ *
+ * This call does not trigger the build. Instead next time Maven builder
+ * processes the project it will use goals to execute during clean
+ * build regardless of the build type requested.
+ *
+ * The main purpose of this call is to allow coordination between multiple
+ * builders configured for the same project.
+ */
+ public void requestFullMavenBuild(IProject project) throws CoreException {
+ project.setSessionProperty(IMavenConstants.FULL_MAVEN_BUILD, Boolean.TRUE);
+ }
+
+ /**
+ * PROVISIONAL
+ */
+ public MavenExecutionRequest createExecutionRequest(IFile pom, ResolverConfiguration resolverConfiguration, IProgressMonitor monitor) throws CoreException {
+ return manager.createExecutionRequest(pom, resolverConfiguration, monitor);
+ }
+
+ /**
+ * PROVISIONAL
+ */
+ public MavenExecutionRequest createExecutionRequest(IMavenProjectFacade project, IProgressMonitor monitor) throws CoreException {
+ return manager.createExecutionRequest(project.getPom(), project.getResolverConfiguration(), monitor);
+ }
+
+ /**
+ * Local repository implementation that checks artifacts in workspace first.
+ *
+ * PROVISIONAL
+ */
+ public MavenArtifactRepository getWorkspaceLocalRepository() throws CoreException {
+ return manager.getWorkspaceLocalRepository();
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectPomScanner.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectPomScanner.java
new file mode 100644
index 00000000..fe73112f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectPomScanner.java
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Parent;
+import org.apache.maven.model.Profile;
+import org.apache.maven.model.Scm;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.embedder.MavenModelManager;
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * Maven project scanner using dependency list
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenProjectPomScanner<T> extends AbstractProjectScanner<MavenProjectScmInfo> {
+
+ private final boolean developer;
+
+ private final Dependency[] dependencies;
+
+ private MavenConsole console;
+
+ private IMaven maven;
+
+ public MavenProjectPomScanner(boolean developer, Dependency[] dependencies, //
+ MavenModelManager modelManager, MavenConsole console) {
+ this.developer = developer;
+ this.dependencies = dependencies;
+ this.console = console;
+ this.maven = MavenPlugin.getDefault().getMaven();
+ }
+
+ public String getDescription() {
+ if(dependencies.length==1) {
+ Dependency d = dependencies[0];
+ return d.getGroupId() + ":" + d.getArtifactId() + ":" + d.getVersion() + (d.getClassifier()==null ? "" : ":" + d.getClassifier()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+ return "" + dependencies.length + " projects"; //$NON-NLS-1$
+ }
+
+ public void run(IProgressMonitor monitor) throws InterruptedException {
+ for(int i = 0; i < dependencies.length; i++ ) {
+ if(monitor.isCanceled()) {
+ throw new InterruptedException();
+ }
+
+ Dependency d = dependencies[i];
+
+ try {
+ Model model = resolveModel(d.getGroupId(), d.getArtifactId(), d.getVersion(), monitor);
+ if(model==null) {
+ String msg = "Can't resolve " + d.getArtifactId();
+ console.logError(msg);
+ addError(new Exception(msg));
+ continue;
+ }
+
+ Scm scm = resolveScm(model, monitor);
+ if(scm==null) {
+ String msg = "No SCM info for " + d.getArtifactId();
+ console.logError(msg);
+ addError(new Exception(msg));
+ continue;
+ }
+
+ String tag = scm.getTag();
+
+ console.logMessage(d.getArtifactId());
+ console.logMessage("Connection: " + scm.getConnection());
+ console.logMessage(" dev: " + scm.getDeveloperConnection());
+ console.logMessage(" url: " + scm.getUrl());
+ console.logMessage(" tag: " + tag);
+
+ String connection;
+ if(developer) {
+ connection = scm.getDeveloperConnection();
+ if(connection==null) {
+ String msg = d.getArtifactId() + " doesn't specify developer SCM connection";
+ console.logError(msg);
+ addError(new Exception(msg));
+ continue;
+ }
+ } else {
+ connection = scm.getConnection();
+ if(connection==null) {
+ String msg = d.getArtifactId() + " doesn't specify SCM connection";
+ console.logError(msg);
+ addError(new Exception(msg));
+ continue;
+ }
+ }
+
+ // connection: scm:svn:https://svn.apache.org/repos/asf/incubator/wicket/branches/wicket-1.2.x/wicket
+ // dev: scm:svn:https://svn.apache.org/repos/asf/incubator/wicket/branches/wicket-1.2.x/wicket
+ // url: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.2.x/wicket
+ // tag: HEAD
+
+ // TODO add an option to select all modules/projects and optimize scan
+
+ if(connection.endsWith("/")) { //$NON-NLS-1$
+ connection = connection.substring(0, connection.length()-1);
+ }
+
+ int n = connection.lastIndexOf("/"); //$NON-NLS-1$
+ String label = (n == -1 ? connection : connection.substring(n)) + "/" + IMavenConstants.POM_FILE_NAME; //$NON-NLS-1$
+
+ addProject(new MavenProjectScmInfo(label, model, null, tag, connection, connection));
+
+ } catch(Exception ex) {
+ addError(ex);
+ String msg = "Error reading " + d.getArtifactId();
+ console.logError(msg);
+ MavenLogger.log(msg, ex);
+ }
+ }
+ }
+
+ private Scm resolveScm(Model model, IProgressMonitor monitor) throws ArtifactResolutionException,
+ ArtifactNotFoundException, XmlPullParserException, IOException, CoreException {
+ Scm scm = model.getScm();
+ if(scm != null) {
+ return scm;
+ }
+
+ Parent parent = model.getParent();
+ if(parent == null) {
+ return null;
+ }
+
+ Model parentModel = resolveModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion(), monitor);
+ if(parentModel==null) {
+ return null;
+ }
+
+ Scm parentScm = resolveScm(parentModel, monitor);
+ if(parentScm==null) {
+ return null;
+ }
+
+ Set<String> modules = new HashSet<String>(parentModel.getModules());
+ List<Profile> parentModelProfiles = parentModel.getProfiles();
+ for(Profile profile : parentModelProfiles) {
+ modules.addAll(profile.getModules());
+ }
+
+ // heuristics for matching module names to artifactId
+ String artifactId = model.getArtifactId();
+ for(String module : modules) {
+ if(module.equals(artifactId) || module.endsWith("/" + artifactId)) { //$NON-NLS-1$
+ if(parentScm.getConnection()!=null) {
+ parentScm.setConnection(parentScm.getConnection() + "/" + module); //$NON-NLS-1$
+ }
+ if(parentScm.getDeveloperConnection()!=null) {
+ parentScm.setDeveloperConnection(parentScm.getDeveloperConnection() + "/" + module); //$NON-NLS-1$
+ }
+ return parentScm;
+ }
+ }
+
+ // XXX read modules from profiles
+
+ return parentScm;
+ }
+
+ private Model resolveModel(String groupId, String artifactId, String version, IProgressMonitor monitor)
+ throws CoreException {
+ monitor.subTask(NLS.bind(Messages.MavenProjectPomScanner_task_resolving, new Object[] { groupId, artifactId, version}));
+
+ List<ArtifactRepository> repositories = maven.getArtifactRepositories();
+ Artifact artifact = maven.resolve(groupId, artifactId, version, "pom", null, repositories, monitor); //$NON-NLS-1$
+
+ File file = artifact.getFile();
+ if(file == null) {
+ return null;
+ }
+
+ // XXX this fail on reading extensions
+ // MavenProject project = embedder.readProject(file);
+
+ monitor.subTask(NLS.bind(Messages.MavenProjectPomScanner_23, new Object[] {groupId, artifactId, version}));
+ return maven.readModel(file);
+ }
+
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectScmInfo.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectScmInfo.java
new file mode 100644
index 00000000..fc810dfa
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectScmInfo.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import java.io.File;
+
+import org.apache.maven.model.Model;
+
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class MavenProjectScmInfo extends MavenProjectInfo {
+
+ private final String folderUrl;
+ private final String repositoryUrl;
+ private final String revision;
+ private final String branch;
+
+ private String username;
+ private String password;
+
+ private File sslCertificate;
+ private String sslCertificatePassphrase;
+
+ public MavenProjectScmInfo(String label, Model model, MavenProjectInfo parent, //
+ String revision, String folderUrl, String repositoryUrl) {
+ this(label, model, parent, null, revision, folderUrl, repositoryUrl);
+ }
+
+ public MavenProjectScmInfo(String label, Model model, MavenProjectInfo parent, //
+ String branch, String revision, String folderUrl, String repositoryUrl) {
+ super(label, null, model, parent);
+ this.revision = revision;
+ this.folderUrl = folderUrl;
+ this.repositoryUrl = repositoryUrl;
+ this.branch = branch;
+ }
+
+ public String getBranch() {
+ return this.branch;
+ }
+
+ public String getRevision() {
+ return this.revision;
+ }
+
+ public String getFolderUrl() {
+ return folderUrl;
+ }
+
+ public String getRepositoryUrl() {
+ return repositoryUrl;
+ }
+
+ public boolean equals(Object obj) {
+ if(obj instanceof MavenProjectScmInfo) {
+ MavenProjectScmInfo info = (MavenProjectScmInfo) obj;
+ return folderUrl.equals(info.getFolderUrl());
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return folderUrl.hashCode();
+ }
+
+ public String toString() {
+ return getLabel() + " " + folderUrl; //$NON-NLS-1$
+ }
+
+ public String getUsername() {
+ return username;
+ }
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public void setSSLCertificate(File certificate) {
+ this.sslCertificate = certificate;
+ }
+ public File getSSLCertificate() {
+ return sslCertificate;
+ }
+
+ public String getSSLCertificatePassphrase() {
+ return sslCertificatePassphrase;
+ }
+ public void setSSLCertificatePassphrase(String passphrase) {
+ this.sslCertificatePassphrase = passphrase;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectUtils.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectUtils.java
new file mode 100644
index 00000000..cbcf60e6
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenProjectUtils.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import java.io.File;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+import org.apache.maven.model.Resource;
+
+/**
+ * Collection of helper methods to map between MavenProject and IResource.
+ *
+ * @author igor
+ */
+public class MavenProjectUtils {
+
+ private MavenProjectUtils() {
+ }
+
+ /**
+ * Returns project resource for given filesystem location or null the location is outside of project.
+ *
+ * @param resourceLocation absolute filesystem location
+ * @return IPath the full, absolute workspace path resourceLocation
+ */
+ public static IPath getProjectRelativePath(IProject project, String resourceLocation) {
+ if(resourceLocation == null) {
+ return null;
+ }
+ IPath projectLocation = project.getLocation();
+ IPath directory = Path.fromOSString(resourceLocation); // this is an absolute path!
+ if(projectLocation == null || !projectLocation.isPrefixOf(directory)) {
+ return null;
+ }
+
+ return directory.removeFirstSegments(projectLocation.segmentCount()).makeRelative().setDevice(null);
+ }
+
+ public static IPath[] getResourceLocations(IProject project, List<Resource> resources) {
+ LinkedHashSet<IPath> locations = new LinkedHashSet<IPath>();
+ for(Resource resource : resources) {
+ locations.add(getProjectRelativePath(project, resource.getDirectory()));
+ }
+ return locations.toArray(new IPath[locations.size()]);
+ }
+
+ public static IPath[] getSourceLocations(IProject project, List<String> roots) {
+ LinkedHashSet<IPath> locations = new LinkedHashSet<IPath>();
+ for(String root : roots) {
+ IPath path = getProjectRelativePath(project, root);
+ if(path != null) {
+ locations.add(path);
+ }
+ }
+ return locations.toArray(new IPath[locations.size()]);
+ }
+
+ /**
+ * Returns the full, absolute path of the given file relative to the workspace. Returns null if the file does not
+ * exist or is not a member of this project.
+ */
+ public static IPath getFullPath(IProject project, File file) {
+ if (project == null || file == null) {
+ return null;
+ }
+
+ IPath projectPath = project.getLocation();
+ if(projectPath == null) {
+ return null;
+ }
+
+ IPath filePath = new Path(file.getAbsolutePath());
+ if (!projectPath.isPrefixOf(filePath)) {
+ return null;
+ }
+ IResource resource = project.findMember(filePath.removeFirstSegments(projectPath.segmentCount()));
+ if (resource == null) {
+ return null;
+ }
+ return resource.getFullPath();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenUpdateRequest.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenUpdateRequest.java
new file mode 100644
index 00000000..8f936f24
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/MavenUpdateRequest.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+
+/**
+ * Maven project update request
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenUpdateRequest {
+ private boolean offline = false;
+ private boolean updateSnapshots = false;
+ private boolean force = true;
+
+ /**
+ * Set of {@link IFile}
+ */
+ private final Set<IFile> pomFiles = new LinkedHashSet<IFile>();
+
+ public MavenUpdateRequest(boolean offline, boolean updateSnapshots) {
+ this.offline = offline;
+ this.updateSnapshots = updateSnapshots;
+ }
+
+ public MavenUpdateRequest(IProject project, boolean offline, boolean updateSnapshots) {
+ this(offline, updateSnapshots);
+ addPomFile(project);
+ }
+
+ public MavenUpdateRequest(IProject[] projects, boolean offline, boolean updateSnapshots) {
+ this(offline, updateSnapshots);
+
+ for(int i = 0; i < projects.length; i++ ) {
+ addPomFile(projects[i]);
+ }
+ }
+
+ public boolean isOffline() {
+ return this.offline;
+ }
+
+ public boolean isUpdateSnapshots() {
+ return this.updateSnapshots;
+ }
+
+ public void addPomFiles(Set<IFile> pomFiles) {
+ for (IFile pomFile : pomFiles) {
+ addPomFile(pomFile);
+ }
+ }
+
+ public void addPomFile(IFile pomFile) {
+ pomFiles.add(pomFile);
+ }
+
+ public void addPomFile(IProject project) {
+ pomFiles.add(project.getFile(IMavenConstants.POM_FILE_NAME));
+
+ }
+
+ public void removePomFile(IFile pomFile) {
+ pomFiles.remove(pomFile);
+ }
+
+ /**
+ * Returns Set of {@link IFile}
+ */
+ public Set<IFile> getPomFiles() {
+ return this.pomFiles;
+ }
+
+ public boolean isEmpty() {
+ return this.pomFiles.isEmpty();
+ }
+
+ public boolean isForce() {
+ return force;
+ }
+
+ public void setForce(boolean force) {
+ this.force = force;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder("["); //$NON-NLS-1$
+ String sep = ""; //$NON-NLS-1$
+ for(IFile pomFile : pomFiles) {
+ sb.append(sep);
+ sb.append(pomFile.getFullPath());
+ sep = ", "; //$NON-NLS-1$
+ }
+ sb.append("]"); //$NON-NLS-1$
+
+ if(offline) {
+ sb.append(" offline"); //$NON-NLS-1$
+ }
+ if(updateSnapshots) {
+ sb.append(" updateSnapshots"); //$NON-NLS-1$
+ }
+ if(force) {
+ sb.append(" force"); //$NON-NLS-1$
+ }
+
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/ProjectImportConfiguration.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/ProjectImportConfiguration.java
new file mode 100644
index 00000000..e8f8b8bf
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/ProjectImportConfiguration.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.IWorkingSet;
+
+import org.apache.maven.model.Model;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.Messages;
+
+
+/**
+ * Project import configuration bean.
+ */
+public class ProjectImportConfiguration {
+
+ private static final String GROUP_ID = "\\[groupId\\]"; //$NON-NLS-1$
+
+ private static final String ARTIFACT_ID = "\\[artifactId\\]"; //$NON-NLS-1$
+
+ private static final String VERSION = "\\[version\\]"; //$NON-NLS-1$
+
+ /** resolver configuration bean */
+ private ResolverConfiguration resolverConfiguration;
+
+ /** the project name template */
+ private String projectNameTemplate = ""; //$NON-NLS-1$
+
+ private IWorkingSet[] workingSets;
+
+ /** Creates a new configuration. */
+ public ProjectImportConfiguration(ResolverConfiguration resolverConfiguration) {
+ this.resolverConfiguration = resolverConfiguration;
+ }
+
+ /** Creates a new configuration. */
+ public ProjectImportConfiguration() {
+ this(new ResolverConfiguration());
+ }
+
+ /** Returns the resolver configuration bean. */
+ public ResolverConfiguration getResolverConfiguration() {
+ return resolverConfiguration;
+ }
+
+ /** Sets the project name template. */
+ public void setProjectNameTemplate(String projectNameTemplate) {
+ this.projectNameTemplate = projectNameTemplate;
+ }
+
+ /** Returns the project name template. */
+ public String getProjectNameTemplate() {
+ return projectNameTemplate;
+ }
+
+ /** @deprecated UI aspects will be refactored out of core import logic */
+ public void setWorkingSet(IWorkingSet workingSet) {
+ this.workingSets = workingSet == null ? null : new IWorkingSet[]{workingSet};
+ }
+
+ /** @deprecated UI aspects will be refactored out of core import logic */
+ public void setWorkingSets(IWorkingSet[] workingSets) {
+ this.workingSets = workingSets;
+ }
+
+ /** @deprecated UI aspects will be refactored out of core import logic */
+ public IWorkingSet[] getWorkingSets() {
+ return this.workingSets;
+ }
+
+ /**
+ * Calculates the project name for the given model.
+ *
+ * @deprecated This method does not take into account MavenProjectInfo.basedirRename
+ */
+ public String getProjectName(Model model) {
+ // XXX should use resolved MavenProject or Model
+ if(projectNameTemplate.length() == 0) {
+ return model.getArtifactId();
+ }
+
+ String artifactId = model.getArtifactId();
+ String groupId = model.getGroupId();
+ if(groupId == null && model.getParent() != null) {
+ groupId = model.getParent().getGroupId();
+ }
+ String version = model.getVersion();
+ if(version == null && model.getParent() != null) {
+ version = model.getParent().getVersion();
+ }
+
+ // XXX needs MavenProjectManager update to resolve groupId and version
+ return projectNameTemplate.replaceAll(GROUP_ID, groupId).replaceAll(ARTIFACT_ID, artifactId).replaceAll(VERSION,
+ version == null ? "" : version); //$NON-NLS-1$
+ }
+
+ /**
+ * @deprecated This method does not take into account MavenProjectInfo.basedirRename.
+ * Use IMavenProjectImportResult#getProject instead
+ */
+ public IProject getProject(IWorkspaceRoot root, Model model) {
+ return root.getProject(getProjectName(model));
+ }
+
+ /**
+ * @deprecated business logic does not belong to a value object
+ */
+ public IStatus validateProjectName(Model model) {
+ String projectName = getProjectName(model);
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+
+ // check if the project name is valid
+ IStatus nameStatus = workspace.validateName(projectName, IResource.PROJECT);
+ if(!nameStatus.isOK()) {
+ return nameStatus;
+ }
+
+ // check if project already exists
+ if(workspace.getRoot().getProject(projectName).exists()) {
+ return new Status( IStatus.ERROR, IMavenConstants.PLUGIN_ID, 0, Messages.getString("wizard.project.page.project.validator.projectExists",projectName), null); //$NON-NLS-1$
+ }
+
+ return Status.OK_STATUS;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/ResolverConfiguration.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/ResolverConfiguration.java
new file mode 100644
index 00000000..8271bd19
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/ResolverConfiguration.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Resolver configuration holder.
+ *
+ * TODO need a better name, this configures all aspects of maven project in eclipse,
+ * not just dependency resolution.
+ *
+ * @author Eugene Kuleshov
+ */
+public class ResolverConfiguration implements Serializable {
+ private static final long serialVersionUID = 1258510761534886581L;
+
+ private boolean resolveWorkspaceProjects = true;
+
+ private String activeProfiles = ""; //$NON-NLS-1$
+
+ public boolean shouldResolveWorkspaceProjects() {
+ return this.resolveWorkspaceProjects;
+ }
+
+ public String getActiveProfiles() {
+ return this.activeProfiles;
+ }
+
+ public List<String> getActiveProfileList() {
+ if (activeProfiles.trim().length() > 0) {
+ return Arrays.asList(activeProfiles.split("[,\\s\\|]")); //$NON-NLS-1$
+ }
+ return new ArrayList<String>();
+ }
+
+ public void setResolveWorkspaceProjects(boolean resolveWorkspaceProjects) {
+ this.resolveWorkspaceProjects = resolveWorkspaceProjects;
+ }
+
+ public void setActiveProfiles(String activeProfiles) {
+ this.activeProfiles = activeProfiles;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractBuildParticipant.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractBuildParticipant.java
new file mode 100644
index 00000000..ebc79a35
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractBuildParticipant.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.execution.MavenSession;
+
+import org.sonatype.plexus.build.incremental.BuildContext;
+
+import org.eclipse.m2e.core.internal.builder.InternalBuildParticipant;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+
+/**
+ * AbstractMavenBuildParticipant
+ *
+ * @author igor
+ */
+public abstract class AbstractBuildParticipant extends InternalBuildParticipant {
+
+ /**
+ * This method is called during workspace full or incremental build.
+ */
+ public abstract Set<IProject> build(int kind, IProgressMonitor monitor) throws Exception;
+
+ public boolean callOnEmptyDelta() {
+ return false;
+ }
+
+ /**
+ * This method is called during workspace clean build.
+ */
+ @SuppressWarnings("unused")
+ public void clean(IProgressMonitor monitor) throws CoreException {
+ // default implementation does nothing
+ }
+
+ protected IMavenProjectFacade getMavenProjectFacade() {
+ return super.getMavenProjectFacade();
+ }
+
+ protected IResourceDelta getDelta(IProject project) {
+ return super.getDelta(project);
+ }
+
+ protected MavenSession getSession() {
+ return super.getSession();
+ }
+
+ protected BuildContext getBuildContext() {
+ return super.getBuildContext();
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractLifecycleMapping.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractLifecycleMapping.java
new file mode 100644
index 00000000..e64db998
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractLifecycleMapping.java
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.ICommand;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.plugin.MojoExecution;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+
+/**
+ * AbstractLifecycleMapping
+ *
+ * @author igor
+ */
+public abstract class AbstractLifecycleMapping implements ILifecycleMapping {
+
+ private String name;
+
+ private String id;
+
+ private boolean showConfigurators;
+
+ /**
+ * Calls #configure method of all registered project configurators
+ */
+ public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException {
+ addMavenBuilder(request.getProject(), monitor);
+
+ for(AbstractProjectConfigurator configurator : getProjectConfigurators(request.getMavenProjectFacade(), monitor)) {
+ if(monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ configurator.configure(request, monitor);
+ }
+ }
+
+ public void unconfigure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException {
+ for(AbstractProjectConfigurator configurator : getProjectConfigurators(request.getMavenProjectFacade(), monitor)) {
+ if(monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ configurator.unconfigure(request, monitor);
+ }
+ }
+
+ protected static void addMavenBuilder(IProject project, IProgressMonitor monitor) throws CoreException {
+ IProjectDescription description = project.getDescription();
+
+ // ensure Maven builder is always the last one
+ ICommand mavenBuilder = null;
+ ArrayList<ICommand> newSpec = new ArrayList<ICommand>();
+ for(ICommand command : description.getBuildSpec()) {
+ if(IMavenConstants.BUILDER_ID.equals(command.getBuilderName())) {
+ mavenBuilder = command;
+ } else {
+ newSpec.add(command);
+ }
+ }
+ if(mavenBuilder == null) {
+ mavenBuilder = description.newCommand();
+ mavenBuilder.setBuilderName(IMavenConstants.BUILDER_ID);
+ }
+ newSpec.add(mavenBuilder);
+ description.setBuildSpec(newSpec.toArray(new ICommand[newSpec.size()]));
+
+ project.setDescription(description, monitor);
+ }
+
+ /**
+ * @return Returns the name.
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * @param name The name to set.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return Returns the id.
+ */
+ public String getId() {
+ return this.id;
+ }
+
+ /**
+ * @param id The id to set.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * @param show Set whether the project configurators should show. Default is true.
+ */
+ public void setShowConfigurators(boolean show) {
+ this.showConfigurators = show;
+ }
+
+ /**
+ * Returns whether the project configurators will be shown in the UI. Default is true.
+ */
+ public boolean showConfigurators() {
+ return this.showConfigurators;
+ }
+
+ protected List<AbstractBuildParticipant> getBuildParticipants(IMavenProjectFacade facade,
+ List<AbstractProjectConfigurator> configurators, IProgressMonitor monitor) throws CoreException {
+ List<AbstractBuildParticipant> participants = new ArrayList<AbstractBuildParticipant>();
+
+ for(MojoExecution execution : facade.getExecutionPlan(monitor).getMojoExecutions()) {
+ for(AbstractProjectConfigurator configurator : configurators) {
+ if(configurator.isSupportedExecution(execution)) {
+ AbstractBuildParticipant participant = configurator.getBuildParticipant(execution);
+ if(participant != null) {
+ participants.add(participant);
+ }
+ }
+ }
+ }
+
+ return participants;
+ }
+
+ public List<MojoExecution> getNotCoveredMojoExecutions(IMavenProjectFacade mavenProjectFacade,
+ IProgressMonitor monitor) throws CoreException {
+ List<MojoExecution> result = new ArrayList<MojoExecution>();
+
+ List<AbstractProjectConfigurator> projectConfigurators = getProjectConfigurators(mavenProjectFacade, monitor);
+ MavenExecutionPlan mavenExecutionPlan = mavenProjectFacade.getExecutionPlan(monitor);
+ List<MojoExecution> allMojoExecutions = mavenExecutionPlan.getMojoExecutions();
+ for(MojoExecution mojoExecution : allMojoExecutions) {
+ if(!isInterestingPhase(mojoExecution.getLifecyclePhase())) {
+ continue;
+ }
+ boolean isCovered = false;
+ for(AbstractProjectConfigurator configurator : projectConfigurators) {
+ if(configurator.isSupportedExecution(mojoExecution)) {
+ isCovered = true;
+ break;
+ }
+ }
+ if(!isCovered) {
+ result.add(mojoExecution);
+ }
+ }
+ return result;
+ }
+
+ public List<AbstractBuildParticipant> getBuildParticipants(IMavenProjectFacade facade, IProgressMonitor monitor)
+ throws CoreException {
+ List<AbstractProjectConfigurator> configurators = getProjectConfigurators(facade, monitor);
+
+ return getBuildParticipants(facade, configurators, monitor);
+ }
+
+ private static final String[] INTERESTING_PHASES = {"validate", //
+ "initialize", //
+ "generate-sources", //
+ "process-sources", //
+ "generate-resources", //
+ "process-resources", //
+ "compile", //
+ "process-classes", //
+ "generate-test-sources", //
+ "process-test-sources", //
+ "generate-test-resources", //
+ "process-test-resources", //
+ "test-compile", //
+ "process-test-classes", //
+ // "test", //
+ // "prepare-package", //
+ // "package", //
+ //"pre-integration-test", //
+ // "integration-test", //
+ // "post-integration-test", //
+ // "verify", //
+ // "install", //
+ // "deploy", //
+ };
+
+ public boolean isInterestingPhase(String phase) {
+ for(String interestingPhase : INTERESTING_PHASES) {
+ if(interestingPhase.equals(phase)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public abstract List<AbstractProjectConfigurator> getProjectConfigurators(IMavenProjectFacade mavenProjectFacade,
+ IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractProjectConfigurator.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractProjectConfigurator.java
new file mode 100644
index 00000000..d6d51c76
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/AbstractProjectConfigurator.java
@@ -0,0 +1,243 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.PluginExecution;
+import org.apache.maven.plugin.MojoExecution;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.IMavenMarkerManager;
+import org.eclipse.m2e.core.project.IMavenProjectChangedListener;
+import org.eclipse.m2e.core.project.MavenProjectChangedEvent;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+
+
+/**
+ * Used to configure maven projects.
+ *
+ * @author Igor Fedorenko
+ */
+public abstract class AbstractProjectConfigurator implements IExecutableExtension, IMavenProjectChangedListener {
+
+ public static final String ATTR_ID = "id"; //$NON-NLS-1$
+
+ public static final String ATTR_PRIORITY = "priority"; //$NON-NLS-1$
+
+ public static final String ATTR_NAME = "name"; //$NON-NLS-1$
+
+ public static final String ATTR_CLASS = "class"; //$NON-NLS-1$
+
+ private int priority;
+
+ private String id;
+
+ private String name;
+
+ /**
+ * List of maven plugin goal patterns for which this project configurator is enabled automatically. Can be null, in
+ * which case the project configurator can only be enabled explicitly in pom.xml.
+ */
+ protected List<PluginExecutionFilter> pluginExecutionFilters;
+
+ protected MavenProjectManager projectManager;
+
+ protected IMavenConfiguration mavenConfiguration;
+
+ protected IMavenMarkerManager markerManager;
+
+ protected MavenConsole console;
+
+ protected IMaven maven = MavenPlugin.getDefault().getMaven();
+
+ public void setProjectManager(MavenProjectManager projectManager) {
+ this.projectManager = projectManager;
+ }
+
+ public void setMavenConfiguration(IMavenConfiguration mavenConfiguration) {
+ this.mavenConfiguration = mavenConfiguration;
+ }
+
+ public void setMarkerManager(IMavenMarkerManager markerManager) {
+ this.markerManager = markerManager;
+ }
+
+ public void setConsole(MavenConsole console) {
+ this.console = console;
+ }
+
+ /**
+ * Configures Eclipse project passed in ProjectConfigurationRequest, using information from Maven project and other
+ * configuration request parameters
+ * <p>
+ * <i>Should be implemented by subclass</i>
+ *
+ * @param request a project configuration request
+ * @param monitor a progress monitor
+ */
+ public abstract void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Removes Maven specific configuration from the project passed in ProjectConfigurationRequest
+ *
+ * @param request a project un-configuration request
+ * @param monitor a progress monitor
+ */
+ @SuppressWarnings("unused")
+ public void unconfigure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException {
+ }
+
+ /**
+ * Updates project configuration according project changes.
+ * <p>
+ * <i>Can be overwritten by subclass</i>
+ *
+ * @param event a project change event
+ * @param monitor a progress monitor
+ */
+ @SuppressWarnings("unused")
+ public void mavenProjectChanged(MavenProjectChangedEvent event, IProgressMonitor monitor) throws CoreException {
+ }
+
+ // IMavenProjectChangedListener
+
+ public final void mavenProjectChanged(MavenProjectChangedEvent[] events, IProgressMonitor monitor) {
+ for(int i = 0; i < events.length; i++ ) {
+ try {
+ mavenProjectChanged(events[i], monitor);
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+
+ public int getPriority() {
+ return priority;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ // IExecutableExtension
+ public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
+ this.id = config.getAttribute(ATTR_ID);
+ this.name = config.getAttribute(ATTR_NAME);
+ String priorityString = config.getAttribute(ATTR_PRIORITY);
+ try {
+ priority = Integer.parseInt(priorityString);
+ } catch(Exception ex) {
+ priority = Integer.MAX_VALUE;
+ }
+
+ IConfigurationElement[] mojos = config.getChildren("mojo"); //$NON-NLS-1$
+ if(mojos != null && mojos.length > 0) {
+ pluginExecutionFilters = new ArrayList<PluginExecutionFilter>();
+ for(IConfigurationElement mojo : mojos) {
+ String groupId = mojo.getAttribute("groupId"); //$NON-NLS-1$
+ String artifactId = mojo.getAttribute("artifactId"); //$NON-NLS-1$
+ String versionRange = mojo.getAttribute("versionRange"); //$NON-NLS-1$
+ String goals = mojo.getAttribute("goals"); //$NON-NLS-1$
+ addPluginExecutionFilter(groupId, artifactId, versionRange, goals);
+ }
+ }
+ }
+
+ protected void addPluginExecutionFilter(String groupId, String artifactId, String versionRange, String goals) {
+ addPluginExecutionFilter(new PluginExecutionFilter(groupId, artifactId, versionRange, goals));
+ }
+
+ public void addPluginExecutionFilter(PluginExecutionFilter filter) {
+ // TODO validate
+ if(pluginExecutionFilters == null) {
+ pluginExecutionFilters = new ArrayList<PluginExecutionFilter>();
+ }
+ pluginExecutionFilters.add(filter);
+ }
+
+ // TODO move to a helper
+ public static void addNature(IProject project, String natureId, IProgressMonitor monitor) throws CoreException {
+ if(!project.hasNature(natureId)) {
+ IProjectDescription description = project.getDescription();
+ String[] prevNatures = description.getNatureIds();
+ String[] newNatures = new String[prevNatures.length + 1];
+ System.arraycopy(prevNatures, 0, newNatures, 1, prevNatures.length);
+ newNatures[0] = natureId;
+ description.setNatureIds(newNatures);
+ project.setDescription(description, monitor);
+ }
+ }
+
+ @Deprecated
+ protected <T> T getParameterValue(MavenSession session, MojoExecution execution, String parameter, Class<T> asType)
+ throws CoreException {
+ return maven.getMojoParameterValue(session, execution, parameter, asType);
+ }
+
+ protected <T> T getParameterValue(String parameter, Class<T> asType, MavenSession session, MojoExecution mojoExecution)
+ throws CoreException {
+ PluginExecution execution = new PluginExecution();
+ execution.setConfiguration(mojoExecution.getConfiguration());
+ return maven.getMojoParameterValue(parameter, asType, session, mojoExecution.getPlugin(), execution,
+ mojoExecution.getGoal());
+ }
+
+ protected void assertHasNature(IProject project, String natureId) throws CoreException {
+ if(project.getNature(natureId) == null) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ Messages.AbstractProjectConfigurator_error_missing_nature + natureId, null));
+ }
+ }
+
+ @Override
+ public String toString() {
+ return id + ":" + name + "(" + priority + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ public AbstractBuildParticipant getBuildParticipant(MojoExecution execution) {
+ return null;
+ }
+
+ public boolean isSupportedExecution(MojoExecution mojoExecution) {
+ if(pluginExecutionFilters == null) {
+ return false;
+ }
+ for(PluginExecutionFilter key : pluginExecutionFilters) {
+ if(key.match(mojoExecution)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/CustomizableLifecycleMapping.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/CustomizableLifecycleMapping.java
new file mode 100644
index 00000000..762ffd04
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/CustomizableLifecycleMapping.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+
+/**
+ * @author igor
+ */
+public class CustomizableLifecycleMapping extends AbstractLifecycleMapping {
+ public static final String EXTENSION_ID = "customizable"; //$NON-NLS-1$
+
+ private List<AbstractProjectConfigurator> configurators = new ArrayList<AbstractProjectConfigurator>();
+
+ @SuppressWarnings("unused")
+ public List<AbstractProjectConfigurator> getProjectConfigurators(IMavenProjectFacade facade, IProgressMonitor monitor)
+ throws CoreException {
+ return configurators;
+ }
+
+ public void addConfigurator(AbstractProjectConfigurator configurator) {
+ this.configurators.add(configurator);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/DefaultLifecycleMapping.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/DefaultLifecycleMapping.java
new file mode 100644
index 00000000..3f5c2f00
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/DefaultLifecycleMapping.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.plugin.MojoExecution;
+
+import org.eclipse.m2e.core.internal.lifecycle.LifecycleMappingFactory;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+
+/**
+ * DefaultLifecycleMapping
+ *
+ * @author igor
+ */
+public class DefaultLifecycleMapping extends CustomizableLifecycleMapping {
+
+ private static class MojoExecutionKey {
+ private final MojoExecution execution;
+
+ public MojoExecutionKey(MojoExecution execution) {
+ this.execution = execution;
+ }
+
+ public MojoExecution getMojoExecution() {
+ return execution;
+ }
+
+ public int hashCode() {
+ int hash = execution.getGroupId().hashCode();
+ hash = 17 * hash + execution.getArtifactId().hashCode();
+ hash = 17 * hash + execution.getVersion().hashCode();
+ hash = 17 * execution.getGoal().hashCode();
+ return hash;
+ }
+
+ public boolean equals(Object obj) {
+ if(this == obj) {
+ return true;
+ }
+ if(!(obj instanceof MojoExecutionKey)) {
+ return false;
+ }
+
+ MojoExecutionKey other = (MojoExecutionKey) obj;
+
+ return execution.getGroupId().equals(other.execution.getGroupId())
+ && execution.getArtifactId().equals(other.execution.getArtifactId())
+ && execution.getVersion().equals(other.execution.getVersion())
+ && execution.getGoal().equals(other.execution.getGoal());
+ }
+ }
+
+ public List<AbstractProjectConfigurator> getProjectConfigurators(IMavenProjectFacade facade, IProgressMonitor monitor)
+ throws CoreException {
+
+ List<AbstractProjectConfigurator> configurators = super.getProjectConfigurators(facade, monitor);
+
+ Map<MojoExecutionKey, AbstractProjectConfigurator> executions = new LinkedHashMap<MojoExecutionKey, AbstractProjectConfigurator>();
+
+ MavenExecutionPlan executionPlan = facade.getExecutionPlan(monitor);
+ execution: for(MojoExecution execution : executionPlan.getMojoExecutions()) {
+ MojoExecutionKey key = new MojoExecutionKey(execution);
+ for(AbstractProjectConfigurator configurator : configurators) {
+ if(configurator.isSupportedExecution(execution)) {
+ executions.put(key, configurator);
+ continue execution;
+ }
+ }
+ executions.put(key, null);
+ }
+
+ for(Map.Entry<MojoExecutionKey, AbstractProjectConfigurator> entry : executions.entrySet()) {
+ MojoExecutionKey key = entry.getKey();
+ if(entry.getValue() == null) {
+ // make sure to reuse the same instance of project configurator
+ for(AbstractProjectConfigurator configurator : executions.values()) {
+ if(configurator != null && configurator.isSupportedExecution(key.getMojoExecution())) {
+ entry.setValue(configurator);
+ break;
+ }
+ }
+ }
+ if(entry.getValue() == null) {
+ AbstractProjectConfigurator configurator = LifecycleMappingFactory.createProjectConfiguratorFor(key
+ .getMojoExecution());
+ if(configurator != null) {
+ entry.setValue(configurator);
+ }
+ }
+ }
+
+ ArrayList<AbstractProjectConfigurator> result = new ArrayList<AbstractProjectConfigurator>();
+
+ for(AbstractProjectConfigurator configurator : executions.values()) {
+ if(configurator != null && !result.contains(configurator)) {
+ result.add(configurator);
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/ILifecycleMapping.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/ILifecycleMapping.java
new file mode 100644
index 00000000..80ece0df
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/ILifecycleMapping.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.plugin.MojoExecution;
+
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+/**
+ * LifecycleMapping
+ *
+ * @author igor
+ */
+public interface ILifecycleMapping {
+ String getId();
+
+ String getName();
+
+ /**
+ * Configure Eclipse workspace project according to Maven build project configuration.
+ */
+ void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Undo any Eclipse project configuration done during previous call(s) to {@link #configure(ProjectConfigurationRequest, IProgressMonitor)}
+ */
+ void unconfigure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Returns list of AbstractBuildParticipant that need to be executed during
+ * Eclipse workspace build. List can be empty but cannot be null.
+ */
+ List<AbstractBuildParticipant> getBuildParticipants(IMavenProjectFacade facade, IProgressMonitor monitor) throws CoreException;
+
+ /** TODO does this belong here? */
+ List<AbstractProjectConfigurator> getProjectConfigurators(IMavenProjectFacade facade, IProgressMonitor monitor) throws CoreException;
+
+ List<MojoExecution> getNotCoveredMojoExecutions(IMavenProjectFacade mavenProjectFacade, IProgressMonitor monitor)
+ throws CoreException;
+
+ boolean isInterestingPhase(String phase);
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MavenProjectConfigurator.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MavenProjectConfigurator.java
new file mode 100644
index 00000000..204fcb98
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MavenProjectConfigurator.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.model.Build;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.project.ResolverConfiguration;
+
+
+/**
+ * Generic project configurator that using Maven plugins
+ *
+ * @author Eugene Kuleshov
+ * @see AbstractProjectConfigurator
+ */
+public class MavenProjectConfigurator extends AbstractProjectConfigurator {
+
+ String pluginKey;
+
+ List<String> goals;
+
+ public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) {
+ if(pluginKey == null || goals == null) {
+ return;
+ }
+
+ MavenProject mavenProject = request.getMavenProject();
+ Build build = mavenProject.getBuild();
+ if(build != null) {
+ Map<String, Plugin> pluginMap = build.getPluginsAsMap();
+ Plugin mavenPlugin = pluginMap.get(pluginKey);
+ if(mavenPlugin != null) {
+ IFile pomFile = request.getPom();
+ ResolverConfiguration resolverConfiguration = request.getResolverConfiguration();
+ // MavenPlugin plugin = MavenPlugin.getDefault();
+ try {
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+ MavenExecutionRequest executionRequest = projectManager.createExecutionRequest(pomFile, resolverConfiguration, monitor);
+ executionRequest.setGoals(goals);
+ maven.execute(executionRequest, monitor);
+ } catch(Exception ex) {
+ String msg = ex.getMessage() == null ? ex.toString() : ex.getMessage();
+ console.logError(msg);
+ MavenLogger.log(msg, ex);
+ }
+
+ try {
+ request.getProject().refreshLocal(IResource.DEPTH_INFINITE, monitor);
+ } catch(CoreException ex) {
+ IStatus status = ex.getStatus();
+ String msg = status.getMessage();
+ Throwable t = status.getException();
+ console.logError(msg + (t == null ? "" : "; " + t.toString())); //$NON-NLS-1$ //$NON-NLS-2$
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+
+ public String getPluginKey() {
+ return this.pluginKey;
+ }
+
+ public List<String> getGoals() {
+ return this.goals;
+ }
+
+ // IExecutableExtension
+
+ @Override
+ public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
+ super.setInitializationData(config, propertyName, data);
+
+ Pattern pattern = Pattern.compile("(.+?)\\:(.+?)\\|(.+)"); //$NON-NLS-1$
+ String params = (String) data;
+ if(params != null) {
+ Matcher matcher = pattern.matcher(params);
+ if(matcher.find() && matcher.groupCount() == 3) {
+ pluginKey = matcher.group(1) + ":" + matcher.group(2); //$NON-NLS-1$
+ goals = Arrays.asList(matcher.group(3).split("\\|")); //$NON-NLS-1$
+ return;
+ }
+ }
+ MavenLogger.log("Unable to parse configuration for project configurator " + getId() + "; " + data, null); //$NON-NLS-2$
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " " + pluginKey + goals; //$NON-NLS-1$
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MavenResourcesProjectConfigurator.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MavenResourcesProjectConfigurator.java
new file mode 100644
index 00000000..87c013fe
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MavenResourcesProjectConfigurator.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import org.eclipse.m2e.core.internal.project.MojoExecutionProjectConfigurator;
+
+/**
+ * Project configurator for maven-resources-plugin
+ */
+public class MavenResourcesProjectConfigurator extends MojoExecutionProjectConfigurator {
+ public MavenResourcesProjectConfigurator() {
+ super(true /*runOnIncremental*/);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MojoExecutionBuildParticipant.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MojoExecutionBuildParticipant.java
new file mode 100644
index 00000000..f0852f35
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/MojoExecutionBuildParticipant.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.plugin.MojoExecution;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.embedder.IMaven;
+
+
+/**
+ * MojoExecutionBuildParticipant
+ *
+ * @author igor
+ */
+public class MojoExecutionBuildParticipant extends AbstractBuildParticipant {
+
+ private final MojoExecution execution;
+ private final boolean runOnIncremental;
+
+ public MojoExecutionBuildParticipant(MojoExecution execution, boolean runOnIncremental) {
+ this.execution = execution;
+ this.runOnIncremental = runOnIncremental;
+ }
+
+ public Set<IProject> build(int kind, IProgressMonitor monitor) throws Exception {
+ if(appliesToBuildKind(kind)) {
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+
+ maven.execute(getSession(), getMojoExecution(), monitor);
+ }
+ return null;
+ }
+
+ public boolean appliesToBuildKind(int kind) {
+ if(IncrementalProjectBuilder.FULL_BUILD == kind || IncrementalProjectBuilder.CLEAN_BUILD == kind) {
+ return true;
+ }
+ return runOnIncremental;
+ }
+
+ public MojoExecution getMojoExecution() {
+ return execution;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/NoopLifecycleMapping.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/NoopLifecycleMapping.java
new file mode 100644
index 00000000..9273aa71
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/NoopLifecycleMapping.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+
+/**
+ * NoopLifecycleMapping
+ *
+ * @author igor
+ */
+public class NoopLifecycleMapping extends AbstractLifecycleMapping {
+
+ public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException {
+ // do nothing
+ }
+
+ public List<AbstractBuildParticipant> getBuildParticipants(IMavenProjectFacade facade, IProgressMonitor monitor)
+ throws CoreException {
+ return new ArrayList<AbstractBuildParticipant>();
+ }
+
+ public List<AbstractProjectConfigurator> getProjectConfigurators(IMavenProjectFacade facade, IProgressMonitor monitor)
+ throws CoreException {
+ return new ArrayList<AbstractProjectConfigurator>();
+ }
+
+ public void unconfigure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException {
+ // do nothing
+ }
+
+ public List<String> getPotentialMojoExecutionsForBuildKind(IMavenProjectFacade facade, int kind, IProgressMonitor progressMonitor) {
+ return Collections.emptyList();
+ }
+
+ public boolean isInterestingPhase(String phase) {
+ return false;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/PluginExecutionFilter.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/PluginExecutionFilter.java
new file mode 100644
index 00000000..18f8b260
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/PluginExecutionFilter.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.plugin.MojoExecution;
+
+
+public final class PluginExecutionFilter {
+
+ private final String groupId;
+
+ private final String artifactId;
+
+ private final String versionRange;
+
+ private final Set<String> goals;
+
+ private final VersionRange parsedVersionRange;
+
+ public PluginExecutionFilter(String groupId, String artifactId, String versionRange, String goals) {
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.versionRange = versionRange;
+ this.goals = new LinkedHashSet<String>(Arrays.asList(goals.split(","))); //$NON-NLS-1$;
+ try {
+ this.parsedVersionRange = VersionRange.createFromVersionSpec(versionRange);
+ } catch(InvalidVersionSpecificationException e) {
+ throw new IllegalArgumentException("Can't parse version range", e);
+ }
+ }
+
+ public String getVersionRange() {
+ return this.versionRange;
+ }
+
+ public String getGroupId() {
+ return this.groupId;
+ }
+
+ public String getArtifactId() {
+ return this.artifactId;
+ }
+
+ public Set<String> getGoals() {
+ return this.goals;
+ }
+
+ /**
+ * @return true if mojoExecution matches this key or false otherwise
+ */
+ public boolean match(MojoExecution mojoExecution) {
+ if(!groupId.equals(mojoExecution.getGroupId()) || !artifactId.equals(mojoExecution.getArtifactId())) {
+ return false;
+ }
+
+ DefaultArtifactVersion version = new DefaultArtifactVersion(mojoExecution.getVersion());
+
+ if(!parsedVersionRange.containsVersion(version)) {
+ return false;
+ }
+
+ return goals.contains(mojoExecution.getGoal());
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/ProjectConfigurationRequest.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/ProjectConfigurationRequest.java
new file mode 100644
index 00000000..f6f08f49
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/project/configurator/ProjectConfigurationRequest.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.project.configurator;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.ResolverConfiguration;
+
+/**
+ * ProjectConfigurationRequest
+ *
+ * @author igor
+ */
+public class ProjectConfigurationRequest {
+ private final boolean updateSources;
+ private final IMavenProjectFacade facade;
+ private final MavenProject mavenProject;
+ private final MavenSession mavenSession;
+
+ public ProjectConfigurationRequest(IMavenProjectFacade facade, MavenProject mavenProject, MavenSession mavenSession, boolean updateSources) {
+ this.facade = facade;
+ this.mavenSession = mavenSession;
+ this.updateSources = updateSources;
+ this.mavenProject = mavenProject;
+ }
+
+ public IProject getProject() {
+ return facade.getProject();
+ }
+
+ public ResolverConfiguration getResolverConfiguration() {
+ return facade.getResolverConfiguration();
+ }
+
+ public boolean isProjectConfigure() {
+ return updateSources;
+ }
+
+ public boolean isProjectImport() {
+ return !updateSources;
+ }
+
+ public MavenProject getMavenProject() {
+ return mavenProject;
+ }
+
+ public MavenSession getMavenSession() {
+ return mavenSession;
+ }
+
+ public IFile getPom() {
+ return facade.getPom();
+ }
+
+ public IMavenProjectFacade getMavenProjectFacade() {
+ return facade;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/repository/IRepository.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/repository/IRepository.java
new file mode 100644
index 00000000..285cc99e
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/repository/IRepository.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.repository;
+
+import java.io.File;
+
+import org.apache.maven.wagon.authentication.AuthenticationInfo;
+
+/**
+ * Repository tracked by repository registry.
+ *
+ * @author igor
+ */
+public interface IRepository {
+
+ /*
+ * Element/attribute names in settings.xml are quite confusing.
+ *
+ * "server" defines repository access credentials.
+ *
+ * "mirror/id" references server/id, i.e. credentials used to
+ * access the mirror. It does NOT identify the mirror.
+ *
+ * "repository/id" references server/id but also used to override repository
+ * definition. For example, repository with id=central defined in settings.xml
+ * overrides definition of central hardcoded in maven code.
+ *
+ */
+
+ /**
+ * Repository access credentials. Can be null.
+ */
+ public AuthenticationInfo getAuthenticationInfo();
+
+ /**
+ * Repository URL
+ */
+ public String getUrl();
+
+ /**
+ * For local repositories, returns basedir of repository contents.
+ *
+ * Returns null for remote repositories;
+ */
+ public File getBasedir();
+
+ /**
+ * Repository id element as defined in settings.xml or pom.xml file.
+ *
+ * Note that repository id is a reference to server element in settings.xml file,
+ * it does not uniquely identify a repository.
+ */
+ public String getId();
+
+ /**
+ * Unique repository id. Generated based on combination of repository url and userId.
+ * Can be used to store repository-related information on local filesystem.
+ */
+ public String getUid();
+
+ /**
+ * Indicates that repository id matches mirrorOf clause of a mirror. In other
+ * words, all repository requests will be redirected to a mirror.
+ *
+ * If null, repository is accessed directly.
+ *
+ * TODO decide return value format.
+ */
+ public String getMirrorId();
+
+ /**
+ * For repository mirrors, returns value of mirrorOf element as defined in settings.xml.
+ *
+ * Returns null for other repositories.
+ */
+ public String getMirrorOf();
+
+ /**
+ * Protocol part of repository url, i.e. "file", "http", etc.
+ */
+ public String getProtocol();
+
+ public boolean isScope(int scope);
+
+ /**
+ * Human readable repository identifier
+ */
+ public String toString();
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/repository/IRepositoryRegistry.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/repository/IRepositoryRegistry.java
new file mode 100644
index 00000000..5e676adf
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/repository/IRepositoryRegistry.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.repository;
+
+import java.util.List;
+
+import org.eclipse.m2e.core.embedder.ArtifactRepositoryRef;
+
+/**
+ * Registry of repositories accessible by m2e.
+ *
+ * The registry automatically tracks the following repositories
+ *
+ * <dl>
+ * <li>Maven local repository
+ * <li>Workspace repository
+ * <li>Mirrors defined in settings.xml
+ * <li>Repositories and pluginRepositories defined in active profiles in
+ * settings.xml
+ * <li>Repositories and pluginRepositories defined in pom.xml files of
+ * workspace Maven projects.
+ * </dl>
+ *
+ * @author igor
+ */
+public interface IRepositoryRegistry {
+
+ /**
+ *
+ */
+ public static final int SCOPE_UNKNOWN = 1;
+
+ /**
+ * Maven local repositories.
+ */
+ public static final int SCOPE_LOCAL = 1 << 1;
+
+ /**
+ * Eclipse workspace repository
+ */
+ public static final int SCOPE_WORKSPACE = 1 << 2;
+
+ /**
+ * Repositories defined in settings.xml file.
+ */
+ public static final int SCOPE_SETTINGS = 1 << 3;
+
+ /**
+ * Repositories defined in pom.xml files of workspace Maven projects
+ */
+ public static final int SCOPE_PROJECT = 1 << 4;
+
+
+ public List<IRepository> getRepositories(int scope);
+
+ public IRepository getWorkspaceRepository();
+
+ public IRepository getLocalRepository();
+
+ public IRepository getRepository(ArtifactRepositoryRef repositoryRef);
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/MavenCheckoutOperation.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/MavenCheckoutOperation.java
new file mode 100644
index 00000000..abdabde3
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/MavenCheckoutOperation.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.scm;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.MavenProjectScmInfo;
+
+
+/**
+ * Checkout operation
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenCheckoutOperation {
+
+ private final MavenConsole console;
+
+ private final File location;
+
+ private final Collection<MavenProjectScmInfo> mavenProjects;
+
+ private final List<String> locations = new ArrayList<String>();
+
+ public MavenCheckoutOperation(File location, Collection<MavenProjectScmInfo> mavenProjects, MavenConsole console) {
+ this.location = location;
+ this.mavenProjects = mavenProjects;
+ this.console = console;
+ }
+
+ public void run(IProgressMonitor monitor) throws InterruptedException, CoreException {
+ List<MavenProjectScmInfo> flatProjects = new ArrayList<MavenProjectScmInfo>();
+
+ // sort nested projects
+ for(MavenProjectScmInfo info : mavenProjects) {
+ if(monitor.isCanceled()) {
+ throw new InterruptedException();
+ }
+
+ String folderUrl = info.getFolderUrl();
+
+ monitor.setTaskName(NLS.bind(Messages.MavenCheckoutOperation_task_scanning, info.getLabel(), info.getFolderUrl()));
+
+ // XXX check if projects already exist
+ boolean isNestedPath = false;
+ for(MavenProjectScmInfo info2 : mavenProjects) {
+ if(info != info2) {
+ String path = info2.getFolderUrl();
+ if(folderUrl.startsWith(path + "/")) { //$NON-NLS-1$
+ isNestedPath = true;
+ break;
+ }
+ }
+ }
+ if(!isNestedPath) {
+ flatProjects.add(info);
+ }
+ }
+
+ for(MavenProjectScmInfo info : flatProjects) {
+ if(monitor.isCanceled()) {
+ throw new InterruptedException();
+ }
+
+ monitor.setTaskName(NLS.bind(Messages.MavenCheckoutOperation_task_checking,info.getLabel(), info.getFolderUrl()));
+
+ // XXX if location is pointing to workspace folder need to create unique dir too
+ File workspaceRoot = ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile();
+ File location = getUniqueDir(this.location == null ? workspaceRoot : this.location);
+
+ ScmHandler handler = ScmHandlerFactory.getHandler(info.getFolderUrl());
+ if(handler == null) {
+ String msg = "SCM provider is not available for " + info.getFolderUrl();
+ console.logError(msg);
+ } else {
+ handler.checkoutProject(info, location, monitor);
+ locations.add(location.getAbsolutePath());
+ }
+
+ }
+
+ }
+
+ protected File getUniqueDir(File baseDir) {
+ long suffix = System.currentTimeMillis();
+ while(true) {
+ File tempDir = new File(baseDir, "maven." + suffix); //$NON-NLS-1$
+ if(!tempDir.exists()) {
+ return tempDir;
+ }
+ suffix++;
+ }
+ }
+
+ /**
+ * @return Returns collection of {@link MavenProjectScmInfo}
+ */
+ public Collection<MavenProjectScmInfo> getMavenProjects() {
+ return this.mavenProjects;
+ }
+
+ /**
+ * @return Returns list of <code>String</code> paths for the checked out locations
+ */
+ public List<String> getLocations() {
+ return this.locations;
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandler.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandler.java
new file mode 100644
index 00000000..9adb53a3
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandler.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.scm;
+
+import java.io.File;
+import java.io.InputStream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.project.MavenProjectScmInfo;
+
+/**
+ * An SCM handler base class
+ *
+ * @author Eugene Kuleshov
+ */
+public abstract class ScmHandler implements Comparable<ScmHandler>, IExecutableExtension {
+
+ public static final String ATTR_CLASS = "class"; //$NON-NLS-1$
+ public static final String ATTR_TYPE = "type"; //$NON-NLS-1$
+ public static final String ATTR_PRIORITY = "priority"; //$NON-NLS-1$
+
+ private String type;
+ private int priority;
+
+ public String getType() {
+ return type;
+ }
+
+ public int getPriority() {
+ return priority;
+ }
+
+ /**
+ * Opens resource from SCM
+ *
+ * @param url an url in maven-scm format for the resource to open
+ * @param revision a resource revision to open
+ *
+ * @throws CoreException when selected resource can't be open
+ *
+ * @see http://maven.apache.org/scm/scm-url-format.html
+ */
+ public InputStream open(String url, String revision) throws CoreException {
+ return null;
+ }
+
+ /**
+ * @param info
+ * @param location
+ * @param monitor
+ */
+ public abstract void checkoutProject(MavenProjectScmInfo info, //
+ File location, IProgressMonitor monitor) throws CoreException, InterruptedException;
+
+ // IExecutableExtension
+
+ public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
+ String handlerClass = config.getAttribute(propertyName);
+ String type = config.getAttribute(ATTR_TYPE);
+ String priority = config.getAttribute(ATTR_PRIORITY);
+
+ this.type = type;
+
+ if(priority!=null) {
+ try {
+ this.priority = Integer.parseInt(priority);
+ } catch(Exception ex) {
+ MavenLogger.log("Unable to parse priority for " + handlerClass, ex);
+ }
+ }
+ }
+
+ // Comparable
+
+ public int compareTo(ScmHandler o) {
+ if(o != null) {
+ ScmHandler handler = o;
+ int res = getType().compareTo(handler.getType());
+ if(res==0) {
+ res = getPriority() - handler.getPriority();
+ }
+ return res;
+ }
+ return -1;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = prime + this.priority;
+ return prime * result + ((this.type == null) ? 0 : this.type.hashCode());
+ }
+
+ public boolean equals(Object obj) {
+ if(this == obj) {
+ return true;
+ }
+ if(obj == null) {
+ return false;
+ }
+ if(getClass() != obj.getClass()) {
+ return false;
+ }
+ ScmHandler other = (ScmHandler) obj;
+ if(this.priority != other.priority) {
+ return false;
+ }
+ if(this.type == null) {
+ if(other.type != null) {
+ return false;
+ }
+ } else if(!this.type.equals(other.type)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandlerFactory.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandlerFactory.java
new file mode 100644
index 00000000..8d3c7d92
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandlerFactory.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.scm;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+
+
+/**
+ * An SCM handler factory
+ *
+ * @author Eugene Kuleshov
+ */
+public class ScmHandlerFactory {
+
+
+ public static final String EXTENSION_SCM_HANDLERS = IMavenConstants.PLUGIN_ID + ".scmHandlers"; //$NON-NLS-1$
+
+ public static final String EXTENSION_SCM_HANDLERS_UI = IMavenConstants.PLUGIN_ID + ".scmHandlersUi"; //$NON-NLS-1$
+
+ private static final String ELEMENT_SCM_HANDLER = "handler"; //$NON-NLS-1$
+
+ private static final String ELEMENT_SCM_HANDLER_UI = "handlerUi"; //$NON-NLS-1$
+
+ private static volatile Map<String, List<ScmHandler>> scms;
+
+ private static volatile Map<String, ScmHandlerUi> scmUis;
+
+ public static synchronized void addScmHandlerUi(ScmHandlerUi handlerUi) {
+ getScmUis().put(handlerUi.getType(), handlerUi);
+ }
+
+ public static synchronized ScmHandlerUi getHandlerUiByType(String type) {
+ return type == null ? null : getScmUis().get(type);
+ }
+
+ public static synchronized void addScmHandler(ScmHandler handler) {
+ List<ScmHandler> handlers = getScms().get(handler.getType());
+ if(handlers == null) {
+ handlers = new ArrayList<ScmHandler>();
+ getScms().put(handler.getType(), handlers);
+ }
+ handlers.add(handler);
+ Collections.sort(handlers);
+ }
+
+ public static synchronized String[] getTypes() {
+ Map<String, List<ScmHandler>> scms = getScms();
+ return scms.keySet().toArray(new String[scms.size()]);
+ }
+
+ public static synchronized ScmHandler getHandler(String url) throws CoreException {
+ String type = ScmUrl.getType(url);
+ return getHandlerByType(type);
+ }
+
+ public static synchronized ScmHandler getHandlerByType(String type) {
+ List<ScmHandler> handlers = getScms().get(type);
+ if(handlers == null) {
+ return null;
+ }
+ return handlers.get(0);
+ }
+
+ private static Map<String, List<ScmHandler>> getScms() {
+ if(scms == null) {
+ scms = new TreeMap<String, List<ScmHandler>>();
+ for(ScmHandler scmHandler : readScmHanderExtensions()) {
+ addScmHandler(scmHandler);
+ }
+ }
+ return scms;
+ }
+
+ private static Map<String, ScmHandlerUi> getScmUis() {
+ if(scmUis == null) {
+ scmUis = new TreeMap<String, ScmHandlerUi>();
+ List<ScmHandlerUi> scmHandlerUis = readScmHandlerUiExtensions();
+ for(ScmHandlerUi scmHandlerUi : scmHandlerUis) {
+ addScmHandlerUi(scmHandlerUi);
+ }
+ }
+ return scmUis;
+ }
+
+ private static List<ScmHandler> readScmHanderExtensions() {
+ List<ScmHandler> scmHandlers = new ArrayList<ScmHandler>();
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint scmHandlersExtensionPoint = registry.getExtensionPoint(EXTENSION_SCM_HANDLERS);
+ if(scmHandlersExtensionPoint != null) {
+ IExtension[] scmHandlersExtensions = scmHandlersExtensionPoint.getExtensions();
+ for(IExtension extension : scmHandlersExtensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for(IConfigurationElement element : elements) {
+ if(element.getName().equals(ELEMENT_SCM_HANDLER)) {
+ try {
+ scmHandlers.add((ScmHandler) element.createExecutableExtension(ScmHandler.ATTR_CLASS));
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+ }
+ return scmHandlers;
+ }
+
+ private static List<ScmHandlerUi> readScmHandlerUiExtensions() {
+ ArrayList<ScmHandlerUi> scmHandlerUis = new ArrayList<ScmHandlerUi>();
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint scmHandlersUiExtensionPoint = registry.getExtensionPoint(EXTENSION_SCM_HANDLERS_UI);
+ if(scmHandlersUiExtensionPoint != null) {
+ IExtension[] scmHandlersUiExtensions = scmHandlersUiExtensionPoint.getExtensions();
+ for(IExtension extension : scmHandlersUiExtensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for(IConfigurationElement element : elements) {
+ if(element.getName().equals(ELEMENT_SCM_HANDLER_UI)) {
+ try {
+ scmHandlerUis.add((ScmHandlerUi) element.createExecutableExtension(ScmHandlerUi.ATTR_CLASS));
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+ }
+ return scmHandlerUis;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandlerUi.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandlerUi.java
new file mode 100644
index 00000000..bb8d4ec8
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmHandlerUi.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.scm;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * An SCM handler UI base class
+ *
+ * @author Eugene Kuleshov
+ */
+public abstract class ScmHandlerUi implements IExecutableExtension {
+ public static final String ATTR_TYPE = "type"; //$NON-NLS-1$
+ public static final String ATTR_CLASS = "class"; //$NON-NLS-1$
+
+ private String type;
+
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Show revision/tag browser dialog and allow user to select revision/tag
+ *
+ * @param shell the shell for revison/tag browser dialog
+ * @param scmUrl the current <code>ScmUrl</code>, or null if none
+ * @param scmRevision the current revision, or null if none
+ * @return String selected revision
+ */
+ public String selectRevision(Shell shell, ScmUrl scmUrl, String scmRevision) {
+ return null;
+ }
+
+ /**
+ * Show repository browser dialog and allow user to select location
+ *
+ * @param shell the shell for repository browser dialog
+ * @param scmUrl the current <code>ScmUrl</code>, or null if none
+ * @return ScmUrl for selected location or null if dialog was canceled
+ */
+ public ScmUrl selectUrl(Shell shell, ScmUrl scmUrl) {
+ return null;
+ }
+
+ public boolean isValidUrl(String scmUrl) {
+ return false;
+ }
+
+ public boolean isValidRevision(ScmUrl scmUrl, String scmRevision) {
+ return false;
+ }
+
+ public boolean canSelectUrl() {
+ return false;
+ }
+
+ public boolean canSelectRevision() {
+ return false;
+ }
+
+
+ // IExecutableExtension
+
+ public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
+ this.type = config.getAttribute(ATTR_TYPE);
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmTag.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmTag.java
new file mode 100644
index 00000000..867357ca
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmTag.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.scm;
+
+/**
+ * An SCM wrapper for tags
+ *
+ * @author Eugene Kuleshov
+ */
+public class ScmTag {
+
+ public static enum Type {
+ HEAD, TAG, BRANCH, DATE;
+ }
+
+ private final String name;
+ private final Type type;
+
+
+ public ScmTag(String name) {
+ this(name, null);
+ }
+
+ public ScmTag(String name, Type type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ /**
+ * Returns tag name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns tag type
+ */
+ public Type getType() {
+ return this.type;
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmUrl.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmUrl.java
new file mode 100644
index 00000000..b3eb3ecf
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/scm/ScmUrl.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.scm;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * An SCM URL wrapper used to adapt 3rd party resources:
+ *
+ * <pre>
+ * scm:{scm_provider}:{scm_provider_specific_part}
+ * </pre>
+ *
+ * @see http://maven.apache.org/scm/scm-url-format.html
+ * @see org.eclipse.core.runtime.IAdapterManager
+ *
+ * @author Eugene Kuleshov
+ */
+public class ScmUrl {
+ private final String scmUrl;
+ private final String scmParentUrl;
+ private final ScmTag tag;
+
+ public ScmUrl(String scmUrl) {
+ this(scmUrl, null);
+ }
+
+ public ScmUrl(String scmUrl, String scmParentUrl) {
+ this(scmUrl, null, null);
+ }
+
+ public ScmUrl(String scmUrl, String scmParentUrl, ScmTag tag) {
+ this.scmUrl = scmUrl;
+ this.scmParentUrl = scmParentUrl;
+ this.tag = tag;
+ }
+
+ /**
+ * Return SCM url
+ */
+ public String getUrl() {
+ return scmUrl;
+ }
+
+ /**
+ * Return SCM url for the parent folder
+ */
+ public String getParentUrl() {
+ return scmParentUrl;
+ }
+
+ /**
+ * Return SCM tag
+ */
+ public ScmTag getTag() {
+ return this.tag;
+ }
+
+ /**
+ * Return provider-specific part of the SCM url
+ *
+ * @return
+ */
+ public String getProviderUrl() {
+ try {
+ String type = ScmUrl.getType(scmUrl);
+ return scmUrl.substring(type.length() + 5);
+
+ } catch(CoreException ex) {
+ return null;
+ }
+ }
+
+ public static synchronized String getType(String url) throws CoreException {
+ if(!url.startsWith("scm:")) { //$NON-NLS-1$
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, NLS.bind(Messages.ScmUrl_error, url), null));
+ }
+ int n = url.indexOf(":", 4); //$NON-NLS-1$
+ if(n == -1) {
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, NLS.bind(Messages.ScmUrl_error, url), null));
+ }
+ return url.substring(4, n);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/AbstractMavenDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/AbstractMavenDialog.java
new file mode 100644
index 00000000..37a8d4ad
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/AbstractMavenDialog.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.dialogs;
+
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.dialogs.SelectionStatusDialog;
+
+import org.eclipse.m2e.core.MavenPlugin;
+
+
+/**
+ * A dialog superclass, featuring position and size settings.
+ */
+public abstract class AbstractMavenDialog extends SelectionStatusDialog {
+
+ protected static final String KEY_WIDTH = "width"; //$NON-NLS-1$
+ protected static final String KEY_HEIGHT = "height"; //$NON-NLS-1$
+ private static final String KEY_X = "x"; //$NON-NLS-1$
+ private static final String KEY_Y = "y"; //$NON-NLS-1$
+ protected IDialogSettings settings;
+ private Point location;
+ private Point size;
+
+ /**
+ * @param parent
+ */
+ protected AbstractMavenDialog(Shell parent, String settingsSection) {
+ super(parent);
+
+ IDialogSettings pluginSettings = MavenPlugin.getDefault().getDialogSettings();
+ IDialogSettings settings = pluginSettings.getSection(settingsSection);
+ if(settings == null) {
+ settings = new DialogSettings(settingsSection);
+ settings.put(KEY_WIDTH, 480);
+ settings.put(KEY_HEIGHT, 450);
+ pluginSettings.addSection(settings);
+ }
+ this.settings = settings;
+ }
+
+ protected Point getInitialSize() {
+ Point result = super.getInitialSize();
+ if(size != null) {
+ result.x = Math.max(result.x, size.x);
+ result.y = Math.max(result.y, size.y);
+ Rectangle display = getShell().getDisplay().getClientArea();
+ result.x = Math.min(result.x, display.width);
+ result.y = Math.min(result.y, display.height);
+ }
+ return result;
+ }
+
+ protected Point getInitialLocation(Point initialSize) {
+ Point result = super.getInitialLocation(initialSize);
+ if(location != null) {
+ result.x = location.x;
+ result.y = location.y;
+ Rectangle display = getShell().getDisplay().getClientArea();
+ int xe = result.x + initialSize.x;
+ if(xe > display.width) {
+ result.x -= xe - display.width;
+ }
+ int ye = result.y + initialSize.y;
+ if(ye > display.height) {
+ result.y -= ye - display.height;
+ }
+ }
+ return result;
+ }
+
+ public boolean close() {
+ writeSettings();
+ return super.close();
+ }
+
+ /**
+ * Initializes itself from the dialog settings with the same state as at the
+ * previous invocation.
+ */
+ protected void readSettings() {
+ try {
+ int x = settings.getInt(KEY_X); //$NON-NLS-1$
+ int y = settings.getInt(KEY_Y); //$NON-NLS-1$
+ location = new Point(x, y);
+ } catch(NumberFormatException e) {
+ location = null;
+ }
+ try {
+ int width = settings.getInt(KEY_WIDTH); //$NON-NLS-1$
+ int height = settings.getInt(KEY_HEIGHT); //$NON-NLS-1$
+ size = new Point(width, height);
+
+ } catch(NumberFormatException e) {
+ size = null;
+ }
+ }
+
+ /**
+ * Stores it current configuration in the dialog store.
+ */
+ private void writeSettings() {
+ Point location = getShell().getLocation();
+ settings.put(KEY_X, location.x); //$NON-NLS-1$
+ settings.put(KEY_Y, location.y); //$NON-NLS-1$
+
+ Point size = getShell().getSize();
+ settings.put(KEY_WIDTH, size.x); //$NON-NLS-1$
+ settings.put(KEY_HEIGHT, size.y); //$NON-NLS-1$
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/AddDependencyDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/AddDependencyDialog.java
new file mode 100644
index 00000000..3a19d329
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/AddDependencyDialog.java
@@ -0,0 +1,617 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.dialogs;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+
+import com.ibm.icu.text.DateFormat;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+
+import org.apache.lucene.search.BooleanQuery;
+
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.graph.DependencyNode;
+import org.sonatype.aether.graph.DependencyVisitor;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexManager;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.index.UserInputSearchExpression;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.util.ProposalUtil;
+import org.eclipse.m2e.core.util.search.Packaging;
+import org.eclipse.m2e.core.wizards.MavenPomSelectionComponent;
+import org.eclipse.m2e.core.wizards.WidthGroup;
+import org.eclipse.m2e.model.edit.pom.Dependency;
+import org.eclipse.m2e.model.edit.pom.PomFactory;
+
+
+/**
+ * A Dialog whose primary goal is to allow the user to select a dependency, either by entering the GAV coordinates
+ * manually, or by search through a repository index.
+ *
+ * @author rgould
+ */
+public class AddDependencyDialog extends AbstractMavenDialog {
+
+ public static final String[] SCOPES = new String[] {"compile", "provided", "runtime", "test", "system"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+
+ /*
+ * dependencies under dependencyManagement are permitted to use an the extra "import" scope
+ */
+ public static final String[] DEP_MANAGEMENT_SCOPES = new String[] {"compile", "provided", "runtime", "test", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ "system", "import"}; //$NON-NLS-1$ //$NON-NLS-2$
+
+ protected static final String DIALOG_SETTINGS = AddDependencyDialog.class.getName();
+
+ protected static final long SEARCH_DELAY = 500L; //in milliseconds
+
+ protected String[] scopes;
+
+ protected TreeViewer resultsViewer;
+
+ protected Text queryText;
+
+ protected Text groupIDtext;
+
+ protected Text artifactIDtext;
+
+ protected Text versionText;
+
+ protected Text infoTextarea;
+
+ protected List scopeList;
+
+ protected java.util.List<Dependency> dependencies;
+
+ protected WidthGroup widthGroup;
+
+ /*
+ * Stores selected files from the results viewer. These are later
+ * converted into the above dependencies when OK is pressed.
+ */
+ protected java.util.List<IndexedArtifactFile> artifactFiles;
+
+ protected SearchJob currentSearch;
+
+ protected IProject project;
+
+ protected DependencyNode dependencyNode;
+
+ /*
+ * This is to be run when the dialog is done creating its controls, but
+ * before open() is called
+ */
+ protected Runnable onLoad;
+
+ protected SelectionListener resultsListener;
+
+ /**
+ * The AddDependencyDialog differs slightly in behaviour depending on context. If it is being used to apply a
+ * dependency under the "dependencyManagement" context, the extra "import" scope is available. Set @param
+ * isForDependencyManagement to true if this is case.
+ *
+ * @param parent
+ * @param isForDependencyManagement
+ * @param project the project which contains this POM. Used for looking up indices
+ */
+ public AddDependencyDialog(Shell parent, boolean isForDependencyManagement, IProject project) {
+ super(parent, DIALOG_SETTINGS);
+ this.project = project;
+
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ setTitle(Messages.AddDependencyDialog_title);
+// setStatusLineAboveButtons(true);
+
+ if(!isForDependencyManagement) {
+ this.scopes = SCOPES;
+ } else {
+ this.scopes = DEP_MANAGEMENT_SCOPES;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.Dialog#createDialogArea()
+ */
+ protected Control createDialogArea(Composite parent) {
+ readSettings();
+
+ Composite composite = (Composite) super.createDialogArea(parent);
+
+ widthGroup = new WidthGroup();
+ composite.addControlListener(widthGroup);
+
+ Composite gavControls = createGAVControls(composite);
+ gavControls.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+
+ new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+
+ Composite searchControls = createSearchControls(composite);
+ searchControls.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ Display.getDefault().asyncExec(this.onLoad);
+
+ return composite;
+ }
+
+
+ /**
+ * Sets the up group-artifact-version controls
+ */
+ private Composite createGAVControls(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+
+ GridLayout gridLayout = new GridLayout(4, false);
+ gridLayout.marginWidth = 0;
+ composite.setLayout(gridLayout);
+
+ Label groupIDlabel = new Label(composite, SWT.NONE);
+ groupIDlabel.setText(Messages.AddDependencyDialog_groupId_label);
+ widthGroup.addControl(groupIDlabel);
+
+ groupIDtext = new Text(composite, SWT.BORDER);
+ groupIDtext.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ Label scopeLabel = new Label(composite, SWT.NONE);
+ scopeLabel.setText(Messages.AddDependencyDialog_scope_label);
+
+ scopeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL);
+ scopeList.setItems(scopes);
+ GridData scopeListData = new GridData(SWT.LEFT, SWT.FILL, false, true, 1, 3);
+ scopeListData.heightHint = 20;
+ scopeListData.widthHint = 100;
+ scopeList.setLayoutData(scopeListData);
+ scopeList.setSelection(0);
+
+ Label artifactIDlabel = new Label(composite, SWT.NONE);
+ artifactIDlabel.setText(Messages.AddDependencyDialog_artifactId_label);
+ widthGroup.addControl(artifactIDlabel);
+
+ artifactIDtext = new Text(composite, SWT.BORDER);
+ artifactIDtext.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ Label filler = new Label(composite, SWT.NONE);
+ filler.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 2));
+
+ Label versionLabel = new Label(composite, SWT.NONE);
+ versionLabel.setText(Messages.AddDependencyDialog_version_label);
+ widthGroup.addControl(versionLabel);
+
+ versionText = new Text(composite, SWT.BORDER);
+ versionText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ /*
+ * Fix the tab order (group -> artifact -> version -> scope)
+ */
+ composite.setTabList(new Control[] { groupIDtext, artifactIDtext, versionText, scopeList});
+
+ ProposalUtil.addGroupIdProposal(project, groupIDtext, Packaging.ALL);
+ ProposalUtil.addArtifactIdProposal(project, groupIDtext, artifactIDtext, Packaging.ALL);
+ ProposalUtil.addVersionProposal(project, groupIDtext, artifactIDtext, versionText, Packaging.ALL);
+
+ artifactIDtext.addModifyListener(new ModifyListener() {
+
+ public void modifyText(ModifyEvent e) {
+ updateInfo();
+ }
+ });
+
+ groupIDtext.addModifyListener(new ModifyListener() {
+
+ public void modifyText(ModifyEvent e) {
+ updateInfo();
+ }
+ });
+
+ return composite;
+ }
+
+ void updateInfo() {
+// infoTextarea.setText(""); //$NON-NLS-1$
+ if(dependencyNode == null) {
+ return;
+ }
+ dependencyNode.accept(new DependencyVisitor() {
+
+ public boolean visitLeave(DependencyNode node) {
+ if(node.getDependency() != null && node.getDependency().getArtifact() != null) {
+ Artifact artifact = node.getDependency().getArtifact();
+ if(artifact.getGroupId().equalsIgnoreCase(groupIDtext.getText().trim())
+ && artifact.getArtifactId().equalsIgnoreCase(artifactIDtext.getText().trim())) {
+ infoTextarea.setText(NLS.bind(Messages.AddDependencyDialog_info_transitive,
+ new String[] {artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()}));
+ }
+ return false;
+ }
+ return true;
+ }
+
+ public boolean visitEnter(DependencyNode node) {
+ return true;
+ }
+ });
+
+ }
+
+ private Composite createSearchControls(Composite parent) {
+ SashForm sashForm = new SashForm(parent, SWT.VERTICAL | SWT.SMOOTH);
+ sashForm.setLayout(new FillLayout());
+
+ Composite resultsComposite = new Composite(sashForm, SWT.NONE);
+ GridLayout resultsLayout = new GridLayout(1, false);
+ resultsLayout.marginWidth = 0;
+ resultsComposite.setLayout(resultsLayout);
+
+ Label queryLabel = new Label(resultsComposite, SWT.NONE);
+ queryLabel.setText(Messages.AddDependencyDialog_search_label);
+// widthGroup.addControl(queryLabel);
+
+ queryText = new Text(resultsComposite, SWT.BORDER | SWT.SEARCH);
+ queryText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ queryText.setFocus();
+
+// queryText.setMessage(Messages.AddDependencyDialog_search_message);
+
+ Label resultsLabel = new Label(resultsComposite, SWT.NONE);
+ resultsLabel.setText(Messages.AddDependencyDialog_results_label);
+ resultsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
+// widthGroup.addControl(resultsLabel);
+
+ Tree resultsTree = new Tree(resultsComposite, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION);
+ GridData treeData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ treeData.heightHint = 140;
+ treeData.widthHint = 100;
+ resultsTree.setLayoutData(treeData);
+
+ Composite infoComposite = new Composite(sashForm, SWT.NONE);
+ GridLayout infoLayout = new GridLayout(1, false);
+ infoLayout.marginWidth = 0;
+ infoComposite.setLayout(infoLayout);
+
+ Label infoLabel = new Label(infoComposite, SWT.NONE);
+ infoLabel.setText(Messages.AddDependencyDialog_info_label);
+ infoLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
+// widthGroup.addControl(infoLabel);
+
+ infoTextarea = new Text(infoComposite, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
+ GridData infoData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ infoData.heightHint = 60;
+ infoData.widthHint = 100;
+ infoTextarea.setLayoutData(infoData);
+
+ sashForm.setWeights(new int[] {70, 30});
+
+ /*
+ * Set up TreeViewer for search results
+ */
+
+ resultsViewer = new TreeViewer(resultsTree);
+ resultsViewer.setContentProvider(new MavenPomSelectionComponent.SearchResultContentProvider());
+ //TODO we want to have the artifacts marked for presence and management..
+ resultsViewer.setLabelProvider(new DelegatingStyledCellLabelProvider(new MavenPomSelectionComponent.SearchResultLabelProvider(Collections.EMPTY_SET, Collections.EMPTY_SET,
+ IIndex.SEARCH_ARTIFACT)));
+
+ /*
+ * Hook up events
+ */
+
+ resultsListener = new SelectionListener();
+ resultsViewer.addSelectionChangedListener(resultsListener);
+
+ queryText.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent e) {
+ if(e.keyCode == SWT.ARROW_DOWN) {
+ resultsViewer.getTree().setFocus();
+ }
+ }
+ });
+
+ queryText.addModifyListener(new ModifyListener() {
+
+ public void modifyText(ModifyEvent e) {
+ search(queryText.getText());
+ }
+ });
+
+ return sashForm;
+ }
+
+ /**
+ * Just a short helper method to determine what to display in the text widgets when the user selects multiple objects
+ * in the tree viewer. If the objects have the same value, then we should show that to them, otherwise we show
+ * something like "(multiple selected)"
+ *
+ * @param current
+ * @param newValue
+ * @return
+ */
+ String chooseWidgetText(String current, String newValue) {
+ if(current == null) {
+ return newValue;
+ } else if(!current.equals(newValue)) {
+ return Messages.AddDependencyDialog_multipleValuesSelected;
+ }
+ return current;
+ }
+
+ void appendFileInfo(final StringBuffer buffer, final IndexedArtifactFile file) {
+ buffer.append(" * " + file.fname);
+ if(file.size != -1) {
+ buffer.append(", size: ");
+ if((file.size / 1024 / 1024) > 0) {
+ buffer.append((file.size / 1024 / 1024) + "MB");
+ } else {
+ buffer.append(Math.max(1, file.size / 1024) + "KB");
+ }
+ }
+ buffer.append(", date: " + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT).format(file.date));
+ buffer.append("\n");
+
+ if(dependencyNode != null) {
+ dependencyNode.accept(new DependencyVisitor() {
+
+ public boolean visitEnter(DependencyNode node) {
+ return true;
+ }
+
+ public boolean visitLeave(DependencyNode node) {
+ if(node.getDependency() == null || node.getDependency().getArtifact() == null) {
+ return true;
+ }
+ Artifact artifact = node.getDependency().getArtifact();
+ if(artifact.getGroupId().equalsIgnoreCase(file.group)
+ && artifact.getArtifactId().equalsIgnoreCase(file.artifact)) {
+ buffer.append(NLS.bind(Messages.AddDependencyDialog_transitive_dependency,
+ new String[] {artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()}));
+ /*
+ * DependencyNodes don't know their parents. Determining which transitive dependency
+ * is using the selected dependency is non trivial :(
+ */
+ return false;
+ }
+ return true;
+ }
+ });
+ }
+ }
+
+ protected void search(String query) {
+ if(query == null || query.length() <= 2) {
+ if(this.currentSearch != null) {
+ this.currentSearch.cancel();
+ }
+ } else {
+ IndexManager indexManager = MavenPlugin.getDefault().getIndexManager();
+
+ if(this.currentSearch != null) {
+ this.currentSearch.cancel();
+ }
+
+ this.currentSearch = new SearchJob(query.toLowerCase(), indexManager);
+ this.currentSearch.schedule(SEARCH_DELAY);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.dialogs.SelectionStatusDialog#computeResult()
+ * This is called when OK is pressed. There's no obligation to do anything.
+ */
+ protected void computeResult() {
+ String scope = ""; //$NON-NLS-1$
+ if(scopeList.getSelection().length != 0) {
+ scope = scopeList.getSelection()[0];
+ }
+
+ if(artifactFiles == null || artifactFiles.size() == 1) {
+ Dependency dependency = createDependency(groupIDtext.getText().trim(), artifactIDtext.getText().trim(),
+ versionText.getText().trim(), scope, ""); //$NON-NLS-1$
+ this.dependencies = Collections.singletonList(dependency);
+ } else {
+ this.dependencies = new LinkedList<Dependency>();
+ for(IndexedArtifactFile file : artifactFiles) {
+ Dependency dep = createDependency(file.group, file.artifact, file.version, scope, file.type);
+ this.dependencies.add(dep);
+ }
+ }
+ }
+
+ private Dependency createDependency(String groupID, String artifactID, String version, String scope, String type) {
+ Dependency dependency = PomFactory.eINSTANCE.createDependency();
+ dependency.setGroupId(groupID);
+ dependency.setArtifactId(artifactID);
+ dependency.setVersion(version);
+
+ /*
+ * For scope and type, if the values are the default, don't save them.
+ * This reduces clutter in the XML file (although forces people who don't
+ * know what the defaults are to look them up).
+ */
+ dependency.setScope("compile".equals(scope) ? "" : scope); //$NON-NLS-1$ //$NON-NLS-2$
+ dependency.setType("jar".equals(type) ? "" : type); //$NON-NLS-1$ //$NON-NLS-2$
+
+ return dependency;
+ }
+
+ public java.util.List<Dependency> getDependencies() {
+ return this.dependencies;
+ }
+
+ void setInfo(int status, String message) {
+ updateStatus(new Status(status, IMavenConstants.PLUGIN_ID, message));
+ }
+
+ public final class SelectionListener implements ISelectionChangedListener {
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+ if(selection.isEmpty()) {
+ infoTextarea.setText(""); //$NON-NLS-1$
+ artifactFiles = null;
+ } else {
+ String artifact = null;
+ String group = null;
+ String version = null;
+
+ artifactFiles = new LinkedList<IndexedArtifactFile>();
+ StringBuffer buffer = new StringBuffer();
+ Iterator iter = selection.iterator();
+ while(iter.hasNext()) {
+ Object obj = iter.next();
+ IndexedArtifactFile file = null;
+
+ if(obj instanceof IndexedArtifact) {
+ file = ((IndexedArtifact) obj).getFiles().iterator().next();
+ } else {
+ file = (IndexedArtifactFile) obj;
+ }
+
+ appendFileInfo(buffer, file);
+ artifactFiles.add(file);
+
+ artifact = chooseWidgetText(artifact, file.artifact);
+ group = chooseWidgetText(group, file.group);
+ version = chooseWidgetText(version, file.version);
+ }
+ setInfo(OK, NLS.bind(artifactFiles.size() == 1 ? Messages.AddDependencyDialog_itemSelected : Messages.AddDependencyDialog_itemsSelected, artifactFiles.size()));
+ infoTextarea.setText(buffer.toString());
+ artifactIDtext.setText(artifact);
+ groupIDtext.setText(group);
+ versionText.setText(version);
+
+ boolean enabled = !(artifactFiles.size() > 1);
+ artifactIDtext.setEnabled(enabled);
+ groupIDtext.setEnabled(enabled);
+ versionText.setEnabled(enabled);
+ }
+ }
+ }
+
+ private class SearchJob extends Job {
+
+ private String query;
+
+ private IndexManager indexManager;
+
+ private boolean cancelled = false;
+
+ public SearchJob(String query, IndexManager indexManager) {
+ super(NLS.bind(Messages.AddDependencyDialog_searchingFor, query));
+ this.query = query;
+ this.indexManager = indexManager;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ protected IStatus run(IProgressMonitor monitor) {
+ if(this.cancelled || resultsViewer == null || resultsViewer.getControl() == null
+ || resultsViewer.getControl().isDisposed()) {
+ return Status.CANCEL_STATUS;
+ }
+
+ try {
+ setResults(IStatus.OK, Messages.AddDependencyDialog_searching, Collections.<String, IndexedArtifact> emptyMap());
+ // TODO: before it was searching all indexes, but it should current project? (cstamas)
+ // If not, the change getIndex(project) to getAllIndexes() and done
+ // TODO: cstamas identified this as "user input", true?
+ Map<String, IndexedArtifact> results = indexManager.getIndex(project).search(new UserInputSearchExpression(query), IIndex.SEARCH_ARTIFACT,
+ IIndex.SEARCH_ALL);
+ setResults(IStatus.OK, NLS.bind(Messages.AddDependencyDialog_searchDone, results.size()), results);
+ } catch(BooleanQuery.TooManyClauses exception) {
+ setResults(IStatus.ERROR, Messages.AddDependencyDialog_tooManyResults,
+ Collections.<String, IndexedArtifact> emptyMap());
+ } catch(RuntimeException exception) {
+ setResults(IStatus.ERROR, NLS.bind(Messages.AddDependencyDialog_searchError, exception.toString()),
+ Collections.<String, IndexedArtifact> emptyMap());
+ } catch(CoreException ex) {
+ setResults(IStatus.ERROR, NLS.bind(Messages.AddDependencyDialog_searchError, ex.getMessage()),
+ Collections.<String, IndexedArtifact> emptyMap());
+ MavenLogger.log(ex);
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.jobs.Job#canceling()
+ */
+ protected void canceling() {
+ this.cancelled = true;
+ super.canceling();
+ }
+
+ private void setResults(final int status, final String infoMessage, final Map<String, IndexedArtifact> results) {
+ if(cancelled) {
+ return;
+ }
+
+ Display.getDefault().syncExec(new Runnable() {
+
+ public void run() {
+ setInfo(status, infoMessage);
+ if(results != null && resultsViewer != null && resultsViewer.getControl() != null
+ && !resultsViewer.getControl().isDisposed()) {
+ resultsViewer.setInput(results);
+ }
+ }
+ });
+ }
+
+ }
+
+ public void setDepdencyNode(DependencyNode node) {
+ this.dependencyNode = node;
+ }
+
+ /**
+ * The provided runnable will be called after createDialogArea is done, but before it returns. This provides a way for
+ * long running operations to be executed in such a way as to not block the UI. This is primarily intended to allow
+ * the loading of the dependencyTree. The runnable should load the tree and then call setDependencyNode()
+ *
+ * @param runnable
+ */
+ public void onLoad(Runnable runnable) {
+ this.onLoad = runnable;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/EditDependencyDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/EditDependencyDialog.java
new file mode 100644
index 00000000..4baaaf4f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/EditDependencyDialog.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.dialogs;
+
+import static org.eclipse.m2e.core.util.Util.nvl;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.edit.command.SetCommand;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.util.M2EUtils;
+import org.eclipse.m2e.core.util.ProposalUtil;
+import org.eclipse.m2e.core.util.search.Packaging;
+import org.eclipse.m2e.model.edit.pom.Dependency;
+import org.eclipse.m2e.model.edit.pom.PomPackage;
+
+
+public class EditDependencyDialog extends AbstractMavenDialog {
+ protected static PomPackage POM_PACKAGE = PomPackage.eINSTANCE;
+
+ private static final String[] TYPES = new String[] {"jar", "war", "rar", "ear", "par", "ejb", "ejb-client", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
+ "test-jar", "java-source", "javadoc", "maven-plugin", "pom"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+
+ private EditingDomain editingDomain;
+
+ private IProject project;
+
+ private String[] scopes;
+
+ protected Text groupIdText;
+
+ protected Text artifactIdText;
+
+ protected Text versionText;
+
+ protected Text classifierText;
+
+ protected Combo typeCombo;
+
+ protected Combo scopeCombo;
+
+ protected Text systemPathText;
+
+// protected Button selectSystemPathButton;
+
+ protected Button optionalButton;
+
+ private Dependency dependency;
+
+ public EditDependencyDialog(Shell parent, boolean dependencyManagement, EditingDomain editingDomain, IProject project) {
+ super(parent, EditDependencyDialog.class.getName());
+ this.editingDomain = editingDomain;
+ this.project = project;
+
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ setTitle(Messages.EditDependencyDialog_title);
+
+ if(!dependencyManagement) {
+ scopes = AddDependencyDialog.SCOPES;
+ } else {
+ scopes = AddDependencyDialog.DEP_MANAGEMENT_SCOPES;
+ }
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ readSettings();
+ Composite superComposite = (Composite) super.createDialogArea(parent);
+
+ Composite composite = new Composite(superComposite, SWT.NONE);
+ composite.setLayout(new GridLayout(3, false));
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ Label groupIdLabel = new Label(composite, SWT.NONE);
+ groupIdLabel.setText(Messages.EditDependencyDialog_groupId_label);
+
+ groupIdText = new Text(composite, SWT.BORDER);
+ GridData gd_groupIdText = new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1);
+ gd_groupIdText.horizontalIndent = 4;
+ groupIdText.setLayoutData(gd_groupIdText);
+ ProposalUtil.addGroupIdProposal(project, groupIdText, Packaging.ALL);
+ M2EUtils.addRequiredDecoration(groupIdText);
+
+ Label artifactIdLabel = new Label(composite, SWT.NONE);
+ artifactIdLabel.setText(Messages.EditDependencyDialog_artifactId_label);
+
+ artifactIdText = new Text(composite, SWT.BORDER);
+ GridData gd_artifactIdText = new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1);
+ gd_artifactIdText.horizontalIndent = 4;
+ artifactIdText.setLayoutData(gd_artifactIdText);
+ ProposalUtil.addArtifactIdProposal(project, groupIdText, artifactIdText, Packaging.ALL);
+ M2EUtils.addRequiredDecoration(artifactIdText);
+
+ Label versionLabel = new Label(composite, SWT.NONE);
+ versionLabel.setText(Messages.EditDependencyDialog_version_label);
+
+ versionText = new Text(composite, SWT.BORDER);
+ GridData versionTextData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1);
+ versionTextData.horizontalIndent = 4;
+ versionTextData.widthHint = 200;
+ versionText.setLayoutData(versionTextData);
+ ProposalUtil.addVersionProposal(project, groupIdText, artifactIdText, versionText, Packaging.ALL);
+
+ Label classifierLabel = new Label(composite, SWT.NONE);
+ classifierLabel.setText(Messages.EditDependencyDialog_classifier_label);
+
+ classifierText = new Text(composite, SWT.BORDER);
+ GridData gd_classifierText = new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1);
+ gd_classifierText.horizontalIndent = 4;
+ gd_classifierText.widthHint = 200;
+ classifierText.setLayoutData(gd_classifierText);
+ ProposalUtil
+ .addClassifierProposal(project, groupIdText, artifactIdText, versionText, classifierText, Packaging.ALL);
+
+ Label typeLabel = new Label(composite, SWT.NONE);
+ typeLabel.setText(Messages.EditDependencyDialog_type_label);
+
+ typeCombo = new Combo(composite, SWT.NONE);
+ typeCombo.setItems(TYPES);
+ GridData gd_typeText = new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1);
+ gd_typeText.horizontalIndent = 4;
+ gd_typeText.widthHint = 120;
+ typeCombo.setLayoutData(gd_typeText);
+
+ Label scopeLabel = new Label(composite, SWT.NONE);
+ scopeLabel.setText(Messages.EditDependencyDialog_scope_label);
+
+ scopeCombo = new Combo(composite, SWT.NONE);
+ scopeCombo.setItems(scopes);
+ GridData gd_scopeText = new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1);
+ gd_scopeText.horizontalIndent = 4;
+ gd_scopeText.widthHint = 120;
+ scopeCombo.setLayoutData(gd_scopeText);
+
+ Label systemPathLabel = new Label(composite, SWT.NONE);
+ systemPathLabel.setText(Messages.EditDependencyDialog_systemPath_label);
+
+ systemPathText = new Text(composite, SWT.BORDER);
+ GridData gd_systemPathText = new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1);
+ gd_systemPathText.horizontalIndent = 4;
+ gd_systemPathText.widthHint = 200;
+ systemPathText.setLayoutData(gd_systemPathText);
+
+// selectSystemPathButton = new Button(composite, SWT.NONE);
+// selectSystemPathButton.setText("Select...");
+
+ new Label(composite, SWT.NONE);
+
+ optionalButton = new Button(composite, SWT.CHECK);
+ optionalButton.setText(Messages.EditDependencyDialog_optional_checkbox);
+ GridData gd_optionalButton = new GridData(SWT.LEFT, SWT.TOP, false, false, 2, 1);
+ gd_optionalButton.horizontalIndent = 4;
+ optionalButton.setLayoutData(gd_optionalButton);
+
+ composite.setTabList(new Control[] {groupIdText, artifactIdText, versionText, classifierText, typeCombo,
+ scopeCombo, systemPathText, /*selectSystemPathButton,*/optionalButton});
+
+ setDependency(dependency);
+
+ return superComposite;
+ }
+
+ protected void computeResult() {
+ CompoundCommand compoundCommand = new CompoundCommand();
+ compoundCommand.append(createCommand(groupIdText.getText(), POM_PACKAGE.getDependency_GroupId(), "")); //$NON-NLS-1$
+ compoundCommand.append(createCommand(artifactIdText.getText(), POM_PACKAGE.getDependency_ArtifactId(), "")); //$NON-NLS-1$
+ compoundCommand.append(createCommand(versionText.getText(), POM_PACKAGE.getDependency_Version(), "")); //$NON-NLS-1$
+ compoundCommand.append(createCommand(classifierText.getText(), POM_PACKAGE.getDependency_Classifier(), "")); //$NON-NLS-1$
+ compoundCommand.append(createCommand(typeCombo.getText(), POM_PACKAGE.getDependency_Type(), "jar")); //$NON-NLS-1$
+ compoundCommand.append(createCommand(scopeCombo.getText(), POM_PACKAGE.getDependency_Scope(), "compile")); //$NON-NLS-1$
+ compoundCommand.append(createCommand(systemPathText.getText(), POM_PACKAGE.getDependency_SystemPath(), "")); //$NON-NLS-1$
+ compoundCommand.append(createCommand(String.valueOf(optionalButton.getSelection()),
+ POM_PACKAGE.getDependency_Optional(), "false")); //$NON-NLS-1$
+ editingDomain.getCommandStack().execute(compoundCommand);
+ }
+
+ public void setDependency(Dependency dependency) {
+ this.dependency = dependency;
+
+ if(dependency != null && groupIdText != null && !groupIdText.isDisposed()) {
+ groupIdText.setText(nvl(dependency.getGroupId()));
+ artifactIdText.setText(nvl(dependency.getArtifactId()));
+ versionText.setText(nvl(dependency.getVersion()));
+ classifierText.setText(nvl(dependency.getClassifier()));
+ typeCombo.setText("".equals(nvl(dependency.getType())) ? "jar" : dependency.getType()); //$NON-NLS-1$ //$NON-NLS-2$
+ scopeCombo.setText("".equals(nvl(dependency.getScope())) ? "compile" : dependency.getScope()); //$NON-NLS-1$ //$NON-NLS-2$
+ systemPathText.setText(nvl(dependency.getSystemPath()));
+
+ boolean optional = Boolean.parseBoolean(dependency.getOptional());
+ if(optionalButton.getSelection() != optional) {
+ optionalButton.setSelection(optional);
+ }
+ }
+ }
+
+ private Command createCommand(String value, Object feature, String defaultValue) {
+ return SetCommand.create(editingDomain, dependency, feature,
+ value.length() == 0 || value.equals(defaultValue) ? SetCommand.UNSET_VALUE : value);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/InputHistory.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/InputHistory.java
new file mode 100644
index 00000000..7aca5f83
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/InputHistory.java
@@ -0,0 +1,232 @@
+
+package org.eclipse.m2e.core.ui.dialogs;
+
+import java.beans.Beans;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Control;
+
+import org.eclipse.m2e.core.MavenPlugin;
+
+
+public class InputHistory {
+ /** the history limit */
+ protected static final int MAX_HISTORY = 10;
+
+ /** dialog settings to store input history */
+ protected IDialogSettings dialogSettings;
+
+ /** the Map of field ids to List of comboboxes that share the same history */
+ private Map<String, List<ControlWrapper>> comboMap;
+
+ private List<String> privileged;
+
+ public InputHistory(String sectionName) {
+ this(sectionName, new String[0]);
+ }
+
+ public InputHistory(String sectionName, String[] privileged) {
+ comboMap = new HashMap<String, List<ControlWrapper>>();
+
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ if(plugin != null) {
+ IDialogSettings pluginSettings = plugin.getDialogSettings();
+ dialogSettings = pluginSettings.getSection(sectionName);
+ if(dialogSettings == null) {
+ dialogSettings = pluginSettings.addNewSection(sectionName);
+ pluginSettings.addSection(dialogSettings);
+ }
+ }
+ assert privileged != null;
+ this.privileged = Arrays.asList(privileged);
+ }
+
+ /** Loads the input history from the dialog settings. */
+ public void load() {
+ if(Beans.isDesignTime()) {
+ return;
+ }
+
+ for(Map.Entry<String, List<ControlWrapper>> e : comboMap.entrySet()) {
+ String id = e.getKey();
+ Set<String> items = new LinkedHashSet<String>();
+ String[] itemsArr = dialogSettings.getArray(id);
+ items.addAll(privileged);
+ if(itemsArr != null) {
+ items.addAll(Arrays.asList(itemsArr));
+ }
+ for(ControlWrapper wrapper : e.getValue()) {
+ if(!wrapper.isDisposed()) {
+ wrapper.setItems(items.toArray(new String[0]));
+ }
+ }
+ }
+ }
+
+ /** Saves the input history into the dialog settings. */
+ public void save() {
+ if(Beans.isDesignTime()) {
+ return;
+ }
+
+ for(Map.Entry<String, List<ControlWrapper>> e : comboMap.entrySet()) {
+ String id = e.getKey();
+
+ Set<String> history = new LinkedHashSet<String>(MAX_HISTORY);
+
+ for(ControlWrapper wrapper : e.getValue()) {
+ wrapper.collect();
+ String lastValue = wrapper.text;
+ if(lastValue != null && lastValue.trim().length() > 0) {
+ history.add(lastValue);
+ }
+ }
+
+ ControlWrapper wrapper = e.getValue().iterator().next();
+ String[] items = wrapper.items;
+ if(items != null) {
+ for(int j = 0; j < items.length && history.size() < MAX_HISTORY; j++ ) {
+ // do not store the privileged items if they are not selected.
+ // we eventually inject the same or different set next time
+ if(!privileged.contains(items[j])) {
+ history.add(items[j]);
+ }
+ }
+ }
+
+ dialogSettings.put(id, history.toArray(new String[history.size()]));
+ }
+ }
+
+ /** Adds an input control to the list of fields to save. */
+ public void add(Control combo) {
+ add(null, combo);
+ }
+
+ /** Adds an input control to the list of fields to save. */
+ public void add(String id, final Control combo) {
+ if(combo != null) {
+ if(id == null) {
+ id = String.valueOf(combo.getData("name"));
+ }
+ List<ControlWrapper> combos = comboMap.get(id);
+ if(combos == null) {
+ combos = new ArrayList<ControlWrapper>();
+ comboMap.put(id, combos);
+ }
+ if(combo instanceof Combo) {
+ combos.add(new ComboWrapper((Combo) combo));
+ } else if(combo instanceof CCombo) {
+ combos.add(new CComboWrapper((CCombo) combo));
+ }
+ }
+ }
+
+ abstract private class ControlWrapper {
+ protected Control control;
+
+ protected String text;
+
+ protected String[] items;
+
+ private boolean collected;
+
+ protected ControlWrapper(Control control) {
+ this.control = control;
+ control.addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ collect();
+ }
+ });
+ }
+
+ protected void collect() {
+ if(!collected && !isDisposed()) {
+ text = getText();
+ items = getItems();
+ }
+ collected = true;
+ }
+
+ protected boolean isDisposed() {
+ return control.isDisposed();
+ }
+
+ abstract protected String getText();
+
+ abstract protected String[] getItems();
+
+ abstract protected void setItems(String[] items);
+ }
+
+ private class ComboWrapper extends ControlWrapper {
+ private Combo combo;
+
+ protected ComboWrapper(Combo combo) {
+ super(combo);
+ this.combo = combo;
+ }
+
+ protected String getText() {
+ return combo.getText();
+ }
+
+ protected String[] getItems() {
+ return combo.getItems();
+ }
+
+ protected void setItems(String[] items) {
+ String value = combo.getText();
+ combo.setItems(items);
+ if(value.length() > 0) {
+ // setItems() clears the text input, so we need to restore it
+ combo.setText(value);
+ } else if(items.length > 0) {
+ combo.setText(items[0]);
+ }
+ }
+ }
+
+ private class CComboWrapper extends ControlWrapper {
+ private CCombo combo;
+
+ protected CComboWrapper(CCombo combo) {
+ super(combo);
+ this.combo = combo;
+ }
+
+ protected String getText() {
+ return combo.getText();
+ }
+
+ protected String[] getItems() {
+ try {
+ return combo.getItems();
+ } catch(SWTException swtException) {
+ //CCombo throws this if the list is disposed, but the combo itself is not disposed yet
+ return new String[0];
+ }
+ }
+
+ protected void setItems(String[] items) {
+ String value = combo.getText();
+ combo.setItems(items);
+ if(value.length() > 0) {
+ // setItems() clears the text input, so we need to restore it
+ combo.setText(value);
+ }
+ }
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenGoalSelectionDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenGoalSelectionDialog.java
new file mode 100644
index 00000000..593d8feb
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenGoalSelectionDialog.java
@@ -0,0 +1,359 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.dialogs;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
+import org.eclipse.ui.dialogs.ISelectionStatusValidator;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexManager;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+
+
+public class MavenGoalSelectionDialog extends ElementTreeSelectionDialog {
+
+ Button isQualifiedNameButton;
+
+ boolean isQualifiedName = true;
+
+ public MavenGoalSelectionDialog(Shell parent) {
+ super(parent, new GoalsLabelProvider(), new GoalsContentProvider());
+
+ setTitle(Messages.getString("launch.goalsDialog.title")); //$NON-NLS-1$
+ setMessage(org.eclipse.m2e.core.internal.Messages.MavenGoalSelectionDialog_message);
+ setValidator(new GoalsSelectionValidator());
+ setInput(new Object());
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
+ layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
+ layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+ layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+ composite.setLayout(layout);
+ composite.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ Label selectGoalLabel = new Label(composite, SWT.NONE);
+ selectGoalLabel.setText(org.eclipse.m2e.core.internal.Messages.MavenGoalSelectionDialog_lblSelect);
+
+ final GoalsFilter filter = new GoalsFilter();
+
+ final Text filterText = new Text(composite, SWT.BORDER);
+ GridData gd_filterText = new GridData(SWT.FILL, SWT.CENTER, true, false);
+ gd_filterText.widthHint = 200;
+ filterText.setLayoutData(gd_filterText);
+ filterText.setFocus();
+
+ final TreeViewer treeViewer = createTreeViewer(composite);
+ treeViewer.addFilter(filter);
+
+ GridData data = new GridData(GridData.FILL_BOTH);
+ data.widthHint = 500;
+ data.heightHint = 400;
+ // data.widthHint = convertWidthInCharsToPixels(fWidth);
+ // data.heightHint = convertHeightInCharsToPixels(fHeight);
+
+ final Tree tree = treeViewer.getTree();
+ tree.setLayoutData(data);
+ tree.setFont(parent.getFont());
+
+ filterText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ String text = filterText.getText();
+ filter.setFilter(text);
+ treeViewer.refresh();
+ if(text.trim().length() == 0) {
+ treeViewer.collapseAll();
+ } else {
+ treeViewer.expandAll();
+ }
+ }
+ });
+
+ filterText.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent e) {
+ if(e.keyCode == SWT.ARROW_DOWN) {
+ tree.setFocus();
+ tree.setSelection(tree.getTopItem().getItem(0));
+
+ Object[] elements = ((ITreeContentProvider) treeViewer.getContentProvider()).getElements(null);
+ treeViewer.setSelection(new StructuredSelection(elements[0]));
+ }
+
+ }
+ });
+
+ isQualifiedNameButton = new Button(composite, SWT.CHECK);
+ isQualifiedNameButton.setText(org.eclipse.m2e.core.internal.Messages.MavenGoalSelectionDialog_btnQualified);
+ isQualifiedNameButton.setSelection(true);
+ isQualifiedNameButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ isQualifiedName = isQualifiedNameButton.getSelection();
+ }
+ });
+
+// if (fIsEmpty) {
+// messageLabel.setEnabled(false);
+// treeWidget.setEnabled(false);
+// }
+
+ return composite;
+ }
+
+ public boolean isQualifiedName() {
+ return isQualifiedName;
+ }
+
+ /**
+ * GoalsContentProvider
+ */
+ static class GoalsContentProvider implements ITreeContentProvider {
+ private static Object[] EMPTY = new Object[0];
+
+ private final List<Group> groups = new ArrayList<Group>();
+
+ public GoalsContentProvider() {
+// MavenEmbedderManager embedderManager = MavenPlugin.getDefault().getMavenEmbedderManager();
+// try {
+// MavenEmbedder embedder = embedderManager.getWorkspaceEmbedder();
+// groups.add(new Group(Messages.getString("launch.goalsDialog.lifecycleBuild"), //$NON-NLS-1$
+// null, null, getLifecyclePhases(embedder.getBuildLifecyclePhases())));
+// groups.add(new Group(Messages.getString("launch.goalsDialog.lifecycleSite"), //$NON-NLS-1$
+// null, null, getLifecyclePhases(embedder.getSiteLifecyclePhases())));
+// groups.add(new Group(Messages.getString("launch.goalsDialog.lifecycleClean"), //$NON-NLS-1$
+// null, null, getLifecyclePhases(embedder.getCleanLifecyclePhases())));
+// } catch(Exception e) {
+// MavenLogger.log("Unable to get lifecycle phases", e);
+// }
+
+ IndexManager indexManager = MavenPlugin.getDefault().getIndexManager();
+ try {
+ // TODO: this will search ALL indexes, isn't the right to search _this_ project reposes only?
+ // I did not find (at first glance, maybe was hasty) a way to get IProject
+ Map<String, IndexedArtifact> result = indexManager.getAllIndexes().search(null, IIndex.SEARCH_PLUGIN); //$NON-NLS-1$
+ TreeMap<String, Group> map = new TreeMap<String, Group>();
+ for(IndexedArtifact a : result.values()) {
+ IndexedArtifactFile f = a.getFiles().iterator().next();
+ if(f.prefix != null && f.prefix.length() > 0 && f.goals != null) {
+ List<Entry> goals = new ArrayList<Entry>();
+ for(String goal : f.goals) {
+ if(goal.length() > 0) {
+ goals.add(new Entry(goal, f.prefix, f));
+ }
+ }
+ if(goals.size() > 0) {
+ map.put(f.prefix + ":" + f.group, new Group(f.prefix, f.group, f.artifact, goals)); //$NON-NLS-1$
+ }
+ }
+ }
+ groups.addAll(map.values());
+ } catch(CoreException e) {
+ MavenLogger.log(e);
+ }
+ }
+
+ private List<Entry> getLifecyclePhases(List<?> phases) {
+ List<Entry> entries = new ArrayList<Entry>();
+ for(int i = 0; i < phases.size(); i++ ) {
+ entries.add(new Entry((String) phases.get(i), null, null));
+ }
+ return entries;
+ }
+
+ public Object[] getElements(Object inputElement) {
+ return groups.toArray();
+ }
+
+ public Object[] getChildren(Object parent) {
+ if(parent instanceof Group) {
+ return ((Group) parent).entries.toArray();
+ }
+ return EMPTY;
+ }
+
+ public boolean hasChildren(Object element) {
+ return element instanceof Group;
+ }
+
+ public Object getParent(Object element) {
+ return null;
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ public void dispose() {
+ }
+
+ }
+
+ /**
+ * GoalsLabelProvider
+ */
+ static class GoalsLabelProvider extends LabelProvider {
+ public String getText(Object element) {
+ if(element instanceof Group) {
+ Group g = (Group) element;
+ if(g.groupId == null) {
+ return g.name;
+ }
+ return g.name + " - " + g.groupId + ":" + g.artifactId; //$NON-NLS-1$ //$NON-NLS-2$
+
+ } else if(element instanceof Entry) {
+ return ((Entry) element).name;
+
+ }
+ return super.getText(element);
+ }
+ }
+
+ /**
+ * GoalsFilter
+ */
+ static class GoalsFilter extends ViewerFilter {
+ private String filter;
+
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if(filter == null || filter.trim().length() == 0) {
+ return true;
+ }
+ if(element instanceof Group) {
+ Group g = (Group) element;
+ if(g.name.indexOf(filter) > -1) {
+ return true;
+ }
+ for(Iterator<Entry> it = g.entries.iterator(); it.hasNext();) {
+ Entry e = it.next();
+ if(e.name.indexOf(filter) > -1) {
+ return true;
+ }
+ }
+
+ } else if(element instanceof Entry) {
+ Entry e = (Entry) element;
+ return e.name.indexOf(filter) > -1 || (e.prefix != null && e.prefix.indexOf(filter) > -1);
+
+ }
+ return false;
+ }
+
+ public void setFilter(String filter) {
+ this.filter = filter;
+ }
+ }
+
+ /**
+ * GoalsSelectionValidator
+ */
+ static class GoalsSelectionValidator implements ISelectionStatusValidator {
+ public IStatus validate(Object[] selection) {
+ if(selection.length == 0) {
+ return new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ org.eclipse.m2e.core.internal.Messages.MavenGoalSelectionDialog_error, null);
+ }
+ for(int j = 0; j < selection.length; j++ ) {
+ if(selection[j] instanceof Entry) {
+ continue;
+ }
+ return new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, "", null); //$NON-NLS-1$
+ }
+ return Status.OK_STATUS;
+ }
+ }
+
+ /**
+ * Group
+ */
+ static class Group {
+ public final String name;
+
+ public final String groupId;
+
+ public final String artifactId;
+
+ public final List<Entry> entries;
+
+ public Group(String name, String groupId, String artifactId, List<Entry> entries) {
+ this.name = name;
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.entries = entries;
+ }
+ }
+
+ /**
+ * Entry
+ */
+ public static class Entry {
+ public final String prefix;
+
+ public final String name;
+
+ private final IndexedArtifactFile f;
+
+ public Entry(String name, String prefix, IndexedArtifactFile f) {
+ this.prefix = prefix;
+ this.name = name;
+ this.f = f;
+ }
+
+ public String getName() {
+ return prefix == null ? name : prefix + ":" + name; //$NON-NLS-1$
+ }
+
+ public String getQualifiedName() {
+ // return prefix == null ? name : prefix + ":" + name;
+ return prefix == null ? name : f.group + ":" + f.artifact + ":" + f.version + ":" + name; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenMessageDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenMessageDialog.java
new file mode 100644
index 00000000..ea439f57
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenMessageDialog.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.dialogs;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * MavenMessageDialog
+ *
+ * @author dyocum
+ */
+public class MavenMessageDialog extends MessageDialog {
+
+ private StyledText messageArea;
+ /**
+ * @param parentShell
+ * @param dialogTitle
+ * @param dialogTitleImage
+ * @param dialogMessage
+ * @param dialogImageType
+ * @param dialogButtonLabels
+ * @param defaultIndex
+ */
+ public MavenMessageDialog(Shell parentShell, String dialogTitle, Image dialogTitleImage, String dialogMessage,
+ int dialogImageType, String[] dialogButtonLabels, int defaultIndex) {
+ super(parentShell, dialogTitle, dialogTitleImage, dialogMessage, dialogImageType, dialogButtonLabels, defaultIndex);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.MessageDialog#createCustomArea(org.eclipse.swt.widgets.Composite)
+ */
+ protected Control createCustomArea(Composite parent) {
+ // TODO Auto-generated method createCustomArea
+ this.messageArea = new StyledText(parent, SWT.WRAP|SWT.READ_ONLY|SWT.H_SCROLL|SWT.V_SCROLL|SWT.BORDER);
+ this.messageArea.setLayout(new GridLayout());
+ GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, true);
+ //size hints
+ gd.widthHint = 600;
+ gd.heightHint = 300;
+ messageArea.setLayoutData(gd);
+ return messageArea;
+ }
+
+ /**
+ *
+ * @param parent Parent shell
+ * @param title Title of the dialog
+ * @param label The label shown above the msg.
+ * @param message The actual message to show in the text area.
+ */
+ public static void openInfo(Shell parent, String title, String label, String message) {
+ MavenMessageDialog dialog = new MavenMessageDialog(parent, title, Dialog.getImage(Dialog.DLG_IMG_INFO), // accept
+ label, INFORMATION, new String[] { IDialogConstants.OK_LABEL }, 0); // ok
+ dialog.create();
+ dialog.getMessageArea().setText(message);
+ dialog.getDialogArea().pack(true);
+ dialog.open();
+ return;
+ }
+
+
+ /**
+ * @return Returns the messageArea.
+ */
+ private StyledText getMessageArea() {
+ return messageArea;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenPropertyDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenPropertyDialog.java
new file mode 100644
index 00000000..764714e6
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenPropertyDialog.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.dialogs;
+
+// import org.eclipse.debug.ui.StringVariableSelectionDialog;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.events.VerifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import org.eclipse.m2e.core.core.Messages;
+
+
+public class MavenPropertyDialog extends Dialog {
+
+ private final String title;
+
+ private final String initialName;
+
+ private final String initialValue;
+
+ private final VerifyListener verifyListener;
+
+ protected Text nameText;
+
+ protected Text valueText;
+
+ private String name;
+
+ private String value;
+
+ public MavenPropertyDialog(Shell shell, String title, String initialName, String initialValue, VerifyListener verifyListener) {
+ super(shell);
+ this.title = title;
+ this.initialName = initialName;
+ this.initialValue = initialValue;
+ this.verifyListener = verifyListener;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+ */
+ protected Control createDialogArea(Composite parent) {
+ Composite comp = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout(2, false);
+ gridLayout.marginTop = 7;
+ gridLayout.marginWidth = 12;
+ comp.setLayout(gridLayout);
+
+ Label nameLabel = new Label(comp, SWT.NONE);
+ nameLabel.setText(Messages.getString("launch.propertyDialog.name")); //$NON-NLS-1$;
+ nameLabel.setFont(comp.getFont());
+
+ nameText = new Text(comp, SWT.BORDER | SWT.SINGLE);
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.widthHint = 300;
+ nameText.setLayoutData(gd);
+ nameText.setFont(comp.getFont());
+ nameText.setText(initialName==null ? "" : initialName); //$NON-NLS-1$
+ nameText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ updateButtons();
+ }
+ });
+
+ Label valueLabel = new Label(comp, SWT.NONE);
+ valueLabel.setText(Messages.getString("launch.propertyDialog.value")); //$NON-NLS-1$;
+ valueLabel.setFont(comp.getFont());
+
+ valueText = new Text(comp, SWT.BORDER | SWT.SINGLE);
+ gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.widthHint = 300;
+ valueText.setLayoutData(gd);
+ valueText.setFont(comp.getFont());
+ valueText.setText(initialValue==null ? "" : initialValue); //$NON-NLS-1$
+ valueText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ updateButtons();
+ }
+ });
+
+// if(variables) {
+// Button variablesButton = new Button(comp, SWT.PUSH);
+// variablesButton.setText(Messages.getString("launch.propertyDialog.browseVariables")); //$NON-NLS-1$;
+// gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
+// gd.horizontalSpan = 2;
+// int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+// gd.widthHint = Math.max(widthHint, variablesButton.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
+// variablesButton.setLayoutData(gd);
+// variablesButton.setFont(comp.getFont());
+//
+// variablesButton.addSelectionListener(new SelectionAdapter() {
+// public void widgetSelected(SelectionEvent se) {
+// StringVariableSelectionDialog variablesDialog = new StringVariableSelectionDialog(getShell());
+// if(variablesDialog.open() == IDialogConstants.OK_ID) {
+// String variable = variablesDialog.getVariableExpression();
+// if(variable != null) {
+// valueText.insert(variable.trim());
+// }
+// }
+// }
+// });
+// }
+
+ return comp;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int)
+ */
+ protected void buttonPressed(int buttonId) {
+ if(buttonId == IDialogConstants.OK_ID) {
+ name = nameText.getText();
+ value = valueText.getText();
+ } else {
+ name = null;
+ value = null;
+ }
+ super.buttonPressed(buttonId);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
+ */
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ if(title != null) {
+ shell.setText(title);
+ }
+// if (fInitialValues[0].length() == 0) {
+// PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, IAntUIHelpContextIds.ADD_PROPERTY_DIALOG);
+// } else {
+// PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, IAntUIHelpContextIds.EDIT_PROPERTY_DIALOG);
+// }
+ }
+
+ /**
+ * Enable the OK button if valid input
+ */
+ protected void updateButtons() {
+ String name = nameText.getText().trim();
+ String value = valueText.getText().trim();
+ // verify name
+ Event e = new Event();
+ e.widget = nameText;
+ VerifyEvent ev = new VerifyEvent(e);
+ ev.doit = true;
+ if (verifyListener != null) {
+ ev.text = name;
+ verifyListener.verifyText(ev);
+ }
+ getButton(IDialogConstants.OK_ID).setEnabled((name.length() > 0) && (value.length() > 0) && ev.doit);
+ }
+
+ /**
+ * Enable the buttons on creation.
+ *
+ * @see org.eclipse.jface.window.Window#create()
+ */
+ public void create() {
+ super.create();
+ updateButtons();
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenRepositorySearchDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenRepositorySearchDialog.java
new file mode 100644
index 00000000..206caf68
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/dialogs/MavenRepositorySearchDialog.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.dialogs;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.wizards.MavenPomSelectionComponent;
+
+
+/**
+ * Maven POM Search dialog
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenRepositorySearchDialog extends AbstractMavenDialog {
+ private static final String DIALOG_SETTINGS = MavenRepositorySearchDialog.class.getName();
+
+ private final boolean showScope;
+
+ private final Set<ArtifactKey> artifacts;
+
+ private final Set<ArtifactKey> managed;
+
+ /**
+ * One of
+ * {@link IIndex#SEARCH_ARTIFACT},
+ * {@link IIndex#SEARCH_CLASS_NAME},
+ */
+ private final String queryType;
+
+ private String queryText;
+
+ MavenPomSelectionComponent pomSelectionComponent;
+
+ private IndexedArtifact selectedIndexedArtifact;
+
+ private IndexedArtifactFile selectedIndexedArtifactFile;
+
+ private String selectedScope;
+
+ private Combo scopeCombo;
+
+
+ /**
+ * Create repository search dialog
+ *
+ * @param parent parent shell
+ * @param title dialog title
+ * @param queryType one of
+ * {@link IIndex#SEARCH_ARTIFACT},
+ * {@link IIndex#SEARCH_CLASS_NAME},
+ * @param artifacts Set&lt;Artifact&gt;
+ * @deprecated
+ */
+ public MavenRepositorySearchDialog(Shell parent, String title, String queryType, Set<ArtifactKey> artifacts) {
+ this(parent, title, queryType, artifacts, Collections.<ArtifactKey>emptySet(), false);
+ }
+
+ public MavenRepositorySearchDialog(Shell parent, String title, String queryType, Set<ArtifactKey> artifacts, Set<ArtifactKey> managed) {
+ this(parent, title, queryType, artifacts, managed, false);
+ }
+ /**
+ * @deprecated
+ */
+ public MavenRepositorySearchDialog(Shell parent, String title, String queryType, Set<ArtifactKey> artifacts, boolean showScope) {
+ this(parent, title, queryType, artifacts, Collections.<ArtifactKey>emptySet(), showScope);
+ }
+
+ public MavenRepositorySearchDialog(Shell parent, String title, String queryType, Set<ArtifactKey> artifacts, Set<ArtifactKey> managed, boolean showScope) {
+ super(parent, DIALOG_SETTINGS);
+ this.artifacts = artifacts;
+ this.managed = managed;
+ this.queryType = queryType;
+ this.showScope = showScope;
+
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ setStatusLineAboveButtons(true);
+ setTitle(title);
+ }
+
+ public void setQuery(String query) {
+ this.queryText = query;
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ readSettings();
+
+ Composite composite = (Composite) super.createDialogArea(parent);
+
+ pomSelectionComponent = new MavenPomSelectionComponent(composite, SWT.NONE);
+ pomSelectionComponent.init(queryText, queryType, artifacts, managed);
+
+ pomSelectionComponent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ pomSelectionComponent.addDoubleClickListener(new IDoubleClickListener() {
+ public void doubleClick(DoubleClickEvent event) {
+ if (!pomSelectionComponent.getStatus().matches(IStatus.ERROR)) {
+ okPressedDelegate();
+ }
+ }
+ });
+ pomSelectionComponent.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ updateStatusDelegate(pomSelectionComponent.getStatus());
+ }
+ });
+
+ return composite;
+ }
+
+ protected void createButtonsForButtonBar(Composite parent) {
+ if(showScope) {
+ ((GridLayout) parent.getLayout()).numColumns += 2;
+
+ Label scopeLabel = new Label(parent, SWT.NONE);
+ scopeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ scopeLabel.setText(Messages.MavenRepositorySearchDialog_lblScope);
+
+ scopeCombo = new Combo(parent, SWT.BORDER | SWT.READ_ONLY);
+ scopeCombo.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
+ scopeCombo.setItems(new String[] {"compile", "test", "runtime", "provided", "system", "import"}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
+ scopeCombo.setText(Messages.MavenRepositorySearchDialog_7);
+ }
+
+ super.createButtonsForButtonBar(parent);
+ }
+
+ void okPressedDelegate() {
+ okPressed();
+ }
+
+ void updateStatusDelegate(IStatus status) {
+ updateStatus(status);
+ }
+
+ protected void computeResult() {
+ selectedIndexedArtifact = pomSelectionComponent.getIndexedArtifact();
+ selectedIndexedArtifactFile = pomSelectionComponent.getIndexedArtifactFile();
+ selectedScope = scopeCombo == null ? null : scopeCombo.getText();
+ setResult(Collections.singletonList(selectedIndexedArtifactFile));
+ }
+
+ public IndexedArtifact getSelectedIndexedArtifact() {
+ return this.selectedIndexedArtifact;
+ }
+
+ public IndexedArtifactFile getSelectedIndexedArtifactFile() {
+ return this.selectedIndexedArtifactFile;
+ }
+
+ public String getSelectedScope() {
+ return this.selectedScope;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenAdapterFactory.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenAdapterFactory.java
new file mode 100644
index 00000000..b09ccb05
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenAdapterFactory.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.ui.IActionFilter;
+
+/**
+ * @author Eugene Kuleshov
+ */
+@SuppressWarnings("unchecked")
+public class MavenAdapterFactory implements IAdapterFactory {
+
+ private static final Class[] ADAPTER_TYPES = new Class[] { IActionFilter.class };
+
+ public Class[] getAdapterList() {
+ return ADAPTER_TYPES;
+ }
+
+ public Object getAdapter(final Object adaptable, Class adapterType) {
+ return new IActionFilter() {
+ public boolean testAttribute(Object target, String name, String value) {
+ return "label".equals(name) // //$NON-NLS-1$
+ && value.equals(getStub(adaptable, LabelProviderStub.class).getLabel());
+ }
+
+ private <T> T getStub(final Object o, Class<T> type) {
+ // can't use IWorkbenchAdapter here because it can cause recursion
+ return (T) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] {type}, //
+ new InvocationHandler() {
+ public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
+ try {
+ Method method = o.getClass().getDeclaredMethod(m.getName(), m.getParameterTypes());
+ return method.invoke(o, args);
+ } catch(RuntimeException ex) {
+ return null;
+ } catch(Exception ex) {
+ return null;
+ }
+ }
+ });
+ }
+ };
+ }
+
+ /**
+ * A stub interface to access org.eclipse.jdt.internal.ui.packageview.ClassPathContainer#getLabel()
+ */
+ public interface LabelProviderStub {
+ public String getLabel();
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenConsoleFactory.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenConsoleFactory.java
new file mode 100644
index 00000000..29b62508
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenConsoleFactory.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal;
+
+import org.eclipse.ui.console.IConsoleFactory;
+
+import org.eclipse.m2e.core.MavenPlugin;
+
+/**
+ * Maven Console factory is used to show the console from the "Open Console"
+ * drop-down action in Console view.
+ *
+ * @see org.eclipse.ui.console.consoleFactory extension point.
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenConsoleFactory implements IConsoleFactory {
+
+ public void openConsole() {
+ MavenPlugin.getDefault().getConsole().showConsole();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenConsolePageParticipant.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenConsolePageParticipant.java
new file mode 100644
index 00000000..a8154d4b
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenConsolePageParticipant.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.console.IConsole;
+import org.eclipse.ui.console.IConsoleConstants;
+import org.eclipse.ui.console.IConsolePageParticipant;
+import org.eclipse.ui.part.IPageBookViewPage;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.actions.MavenConsoleRemoveAction;
+import org.eclipse.m2e.core.actions.MavenDebugOutputAction;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
+
+
+
+public class MavenConsolePageParticipant implements IConsolePageParticipant {
+
+ private IAction consoleRemoveAction;
+ private IAction debugAction;
+ private IAction showOnErrorAction;
+ private IAction showOnOutputAction;
+
+ private static final String SHOW_ON_OUTPUT_LBL = Messages.MavenConsolePageParticipant_any;
+ private static final String SHOW_ON_ERR_LBL = Messages.MavenConsolePageParticipant_error;
+
+ public void init(IPageBookViewPage page, IConsole console) {
+ this.consoleRemoveAction = new MavenConsoleRemoveAction();
+ this.debugAction = new MavenDebugOutputAction();
+
+
+ showOnOutputAction = new ShowOnOutputAction(console, SHOW_ON_OUTPUT_LBL);
+ showOnErrorAction = new ShowOnErrorAction(console, SHOW_ON_ERR_LBL);
+
+ IActionBars actionBars = page.getSite().getActionBars();
+ configureToolBar(actionBars.getToolBarManager());
+ }
+
+ private void configureToolBar(IToolBarManager mgr){
+ mgr.appendToGroup(IConsoleConstants.LAUNCH_GROUP, consoleRemoveAction);
+ mgr.prependToGroup(IConsoleConstants.OUTPUT_GROUP, debugAction);
+ mgr.appendToGroup(IConsoleConstants.OUTPUT_GROUP, showOnOutputAction);
+ mgr.appendToGroup(IConsoleConstants.OUTPUT_GROUP, showOnErrorAction);
+ }
+ public void dispose() {
+ this.consoleRemoveAction = null;
+ this.debugAction = null;
+ }
+
+ public void activated() {
+ }
+
+ public void deactivated() {
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ return null;
+ }
+
+
+
+ class ShowOnErrorAction extends MavenShowConsoleAction{
+ public ShowOnErrorAction(IConsole console, String name){
+ super(name);
+ setImageDescriptor(MavenImages.SHOW_CONSOLE_ERR);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.MavenShowConsoleAction#getKey()
+ */
+ protected String getKey() {
+ return MavenPreferenceConstants.P_SHOW_CONSOLE_ON_ERR;
+ }
+ }
+
+ class ShowOnOutputAction extends MavenShowConsoleAction{
+
+ /**
+ * @param console
+ */
+ public ShowOnOutputAction(IConsole console, String name) {
+ super(name);
+ setImageDescriptor(MavenImages.SHOW_CONSOLE_OUT);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.MavenShowConsoleAction#getKey()
+ */
+ protected String getKey() {
+ return MavenPreferenceConstants.P_SHOW_CONSOLE_ON_OUTPUT;
+ }
+
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenShowConsoleAction.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenShowConsoleAction.java
new file mode 100644
index 00000000..42275036
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenShowConsoleAction.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+import org.eclipse.m2e.core.MavenPlugin;
+
+/**
+ * MavenShowConsoleAction
+ *
+ * @author dyocum
+ */
+public abstract class MavenShowConsoleAction extends Action implements IPropertyChangeListener{
+
+ public MavenShowConsoleAction(String name){
+ super(name, IAction.AS_CHECK_BOX);
+ setToolTipText(name);
+ getPreferenceStore().addPropertyChangeListener(this);
+ update();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
+ */
+ public void propertyChange(PropertyChangeEvent event) {
+ String property = event.getProperty();
+ if (property.equals(getKey())) {
+ update();
+ }
+ }
+
+ protected abstract String getKey();
+
+ private void update() {
+ IPreferenceStore store = getPreferenceStore();
+ if (store.getBoolean(getKey())) {
+ // on
+ setChecked(true);
+ } else {
+ // off
+ setChecked(false);
+ }
+ }
+
+ /**
+ * @return
+ */
+ private IPreferenceStore getPreferenceStore() {
+ return MavenPlugin.getDefault().getPreferenceStore();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.action.Action#run()
+ */
+ public void run() {
+ IPreferenceStore store = getPreferenceStore();
+ boolean show = isChecked();
+ store.removePropertyChangeListener(this);
+ store.setValue(getKey(), show);
+ store.addPropertyChangeListener(this);
+ }
+
+ /**
+ * Must be called to dispose this action.
+ */
+ public void dispose() {
+ getPreferenceStore().removePropertyChangeListener(this);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenVersionDecorator.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenVersionDecorator.java
new file mode 100644
index 00000000..c70fa53e
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/MavenVersionDecorator.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.project.IMavenProjectChangedListener;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectChangedEvent;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class MavenVersionDecorator implements ILabelDecorator {
+
+ private Map<ILabelProviderListener, IMavenProjectChangedListener> listeners = new HashMap<ILabelProviderListener, IMavenProjectChangedListener>();
+
+ public Image decorateImage(Image image, Object element) {
+ return null;
+ }
+
+ public String decorateText(String text, Object element) {
+ if(element instanceof IResource) {
+ IResource resource = (IResource) element;
+ IProject project = resource.getProject();
+ if(project!=null) {
+ MavenProjectManager projectManager = MavenPlugin.getDefault().getMavenProjectManager();
+ IMavenProjectFacade facade = projectManager.create(project, new NullProgressMonitor());
+ if(facade!=null) {
+ ArtifactKey mavenProject = facade.getArtifactKey();
+ if(mavenProject!=null) {
+ String name = resource.getName();
+ int start = text.indexOf(name);
+ if(start>-1) {
+ int n = text.indexOf(' ', start + name.length());
+ if(n>-1) {
+ return text.substring(0, n) + " " + mavenProject.getVersion() + text.substring(n); //$NON-NLS-1$
+ }
+ }
+ return text + " " + mavenProject.getVersion(); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public boolean isLabelProperty(Object element, String property) {
+ return false;
+ }
+
+ public void addListener(final ILabelProviderListener listener) {
+ IMavenProjectChangedListener projectChangeListener = new IMavenProjectChangedListener() {
+ public void mavenProjectChanged(MavenProjectChangedEvent[] events, IProgressMonitor monitor) {
+ ArrayList<IResource> pomList = new ArrayList<IResource>();
+ for(int i = 0; i < events.length; i++ ) {
+ // pomList.add(events[i].getSource());
+ if(events[i]!=null && events[i].getMavenProject()!=null) {
+ IFile pom = events[i].getMavenProject().getPom();
+ pomList.add(pom);
+ if(pom.getParent().getType()==IResource.PROJECT) {
+ pomList.add(pom.getParent());
+ }
+ }
+ }
+ listener.labelProviderChanged(new LabelProviderChangedEvent(MavenVersionDecorator.this, pomList.toArray()));
+ }
+ };
+
+ listeners.put(listener, projectChangeListener);
+
+ MavenProjectManager projectManager = MavenPlugin.getDefault().getMavenProjectManager();
+ projectManager.addMavenProjectChangedListener(projectChangeListener);
+ }
+
+ public void removeListener(ILabelProviderListener listener) {
+ IMavenProjectChangedListener projectChangeListener = listeners.get(listener);
+ if(projectChangeListener!=null) {
+ MavenProjectManager projectManager = MavenPlugin.getDefault().getMavenProjectManager();
+ projectManager.removeMavenProjectChangedListener(projectChangeListener);
+ }
+ }
+
+ public void dispose() {
+ // TODO remove all listeners
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/components/TextComboBoxCellEditor.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/components/TextComboBoxCellEditor.java
new file mode 100644
index 00000000..45c0e957
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/components/TextComboBoxCellEditor.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.components;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+
+/**
+ * A TextComboBoxCellEditor to overcome the limitation of the standard ComboBoxCellEditor, which does not allow to edit
+ * plain text values.
+ *
+ * @author Dmitry Platonoff
+ */
+public class TextComboBoxCellEditor extends CellEditor {
+
+ protected String[] items;
+
+
+ protected CCombo combo;
+
+ public TextComboBoxCellEditor(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ protected Control createControl(Composite parent) {
+ combo = new CCombo(parent, getStyle());
+ combo.setFont(parent.getFont());
+
+ combo.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent e) {
+ keyReleaseOccured(e);
+ }
+ });
+ combo.addTraverseListener(new TraverseListener() {
+ public void keyTraversed(TraverseEvent e) {
+ if (e.detail == SWT.TRAVERSE_ESCAPE
+ || e.detail == SWT.TRAVERSE_RETURN) {
+ e.doit = false;
+ }
+ }
+ });
+
+ loadItems();
+
+ return combo;
+ }
+
+ protected Object doGetValue() {
+ Assert.isNotNull(combo);
+ return combo.getText();
+ }
+
+ protected void doSetFocus() {
+ Assert.isNotNull(combo);
+ combo.setFocus();
+ }
+
+ protected void doSetValue(Object value) {
+ Assert.isNotNull(combo);
+ combo.setText(String.valueOf(value));
+ }
+
+ public String[] getItems() {
+ return items;
+ }
+
+ public void setItems(String[] items) {
+ this.items = items;
+ loadItems();
+ }
+
+ protected void loadItems() {
+ if(combo != null && items != null) {
+ combo.setItems(items);
+ }
+ }
+
+ protected void keyReleaseOccured(KeyEvent keyEvent) {
+ if(keyEvent.character == SWT.ESC) {
+ fireCancelEditor();
+ } else if(keyEvent.character == SWT.TAB || keyEvent.character == SWT.CR) {
+ focusLost();
+ }
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/AbstractLifecyclePropertyPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/AbstractLifecyclePropertyPage.java
new file mode 100644
index 00000000..3ce330f1
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/AbstractLifecyclePropertyPage.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.lifecycle;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * AbstractLifecyclePropertyPage
+ * Holds the pieces used in the common lifecycle mapping properties pages.
+ *
+ * @author dyocum
+ */
+public abstract class AbstractLifecyclePropertyPage extends AbstractPropertyPageExtensionPoint implements ILifecyclePropertyPage{
+ private IProject project;
+ private Shell shell;
+
+ public AbstractLifecyclePropertyPage(){
+ }
+
+ public void setupPage(IProject project, Shell shell){
+ this.project = project;
+ this.setShell(shell);
+ }
+
+ public void setProject(IProject project){
+ this.project = project;
+ }
+
+ public IProject getProject(){
+ return project;
+ }
+
+ /**
+ * @param shell The shell to set.
+ */
+ public void setShell(Shell shell) {
+ this.shell = shell;
+ }
+
+ /**
+ * @return Returns the shell.
+ */
+ public Shell getShell() {
+ return shell;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/AbstractPropertyPageExtensionPoint.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/AbstractPropertyPageExtensionPoint.java
new file mode 100644
index 00000000..ace3c250
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/AbstractPropertyPageExtensionPoint.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.lifecycle;
+
+/**
+ * AbstractPropertyPageExtensionPoint
+ *
+ * @author dyocum
+ */
+public class AbstractPropertyPageExtensionPoint implements ILifecyclePropertyPageExtensionPoint {
+
+ private String name;
+ private String id;
+ private String lifecycleMappingId;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.lifecycle.ILifecyclePropertyPageExtensionPoint#getLifecycleMappingId()
+ */
+ public String getLifecycleMappingId() {
+ return lifecycleMappingId;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.lifecycle.ILifecyclePropertyPageExtensionPoint#getName()
+ */
+ public String getName() {
+ return name;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.lifecycle.ILifecyclePropertyPageExtensionPoint#getPageId()
+ */
+ public String getPageId() {
+ return id;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.lifecycle.ILifecyclePropertyPageExtensionPoint#setLifecycleMappingId(java.lang.String)
+ */
+ public void setLifecycleMappingId(String lifecycleMappingId) {
+ this.lifecycleMappingId = lifecycleMappingId;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.lifecycle.ILifecyclePropertyPageExtensionPoint#setName()
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.lifecycle.ILifecyclePropertyPageExtensionPoint#setPageId()
+ */
+ public void setPageId(String id) {
+ this.id = id;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ILifecyclePropertyPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ILifecyclePropertyPage.java
new file mode 100644
index 00000000..bbc88239
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ILifecyclePropertyPage.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.lifecycle;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * ILifecyclePropertyPage
+ *
+ * @author dyocum
+ */
+public interface ILifecyclePropertyPage extends ILifecyclePropertyPageExtensionPoint{
+ /**
+ * Create and return the composite which will be shown in the parent properties page.
+ * @param parent
+ * @return
+ */
+ public Control createContents(Composite parent);
+
+ /**
+ * Called when the 'Restore Defaults' button is pressed in the properties page.
+ */
+ public void performDefaults();
+
+ /**
+ * Called when the 'OK' or 'Apply' buttons are pressed in the properties dialog.
+ * @return
+ */
+ public boolean performOk();
+
+ /**
+ * The project that these lifecycle mapping properties apply to
+ * @param project
+ */
+ public void setProject(IProject project);
+
+ public IProject getProject();
+
+ /**
+ * The parent shell used for showing error messages.
+ * @param shell
+ */
+ public void setShell(Shell shell);
+
+ public Shell getShell();
+
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ILifecyclePropertyPageExtensionPoint.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ILifecyclePropertyPageExtensionPoint.java
new file mode 100644
index 00000000..a81284da
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ILifecyclePropertyPageExtensionPoint.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.lifecycle;
+
+/**
+ * ILifecyclePropertyPageExtensionPoint
+ *
+ * @author dyocum
+ */
+public interface ILifecyclePropertyPageExtensionPoint {
+ /**
+ * The name of the page. This will be displayed in the title of the properties page.
+ * @return
+ */
+ public String getName();
+
+ /**
+ * Name of the page, called when the extension point is read in
+ */
+ public void setName(String name);
+
+ /**
+ * Get the id of the property page as defined in the extension point
+ * @return
+ */
+ public String getPageId();
+
+ /**
+ * Set the id of the property page, called when extension point is read
+ */
+ public void setPageId(String id);
+
+ /**
+ * Sets the id of the lifecycle mapping strategy that this property page is
+ * associated with
+ * @param lifecycleMappingId
+ */
+ public void setLifecycleMappingId(String lifecycleMappingId);
+
+ /**
+ * Gets the id of the lifecycle mapping strategy
+ * @return
+ */
+ public String getLifecycleMappingId();
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/LifecycleMappingPropertyPageFactory.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/LifecycleMappingPropertyPageFactory.java
new file mode 100644
index 00000000..2be8b931
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/LifecycleMappingPropertyPageFactory.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.lifecycle;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.IProjectConfigurationManager;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.project.ResolverConfiguration;
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+
+
+/**
+ * LifecycleMappingPropertyPageFactory
+ *
+ * @author dyocum
+ */
+public class LifecycleMappingPropertyPageFactory {
+
+ public static final String EXTENSION_LIFECYCLE_MAPPING_PROPERTY_PAGE = IMavenConstants.PLUGIN_ID + ".lifecycleMappingPropertyPage"; //$NON-NLS-1$
+
+ private static final String ATTR_LIFECYCLE_MAPPING_ID = "lifecycleMappingId"; //$NON-NLS-1$
+
+ private static final String ATTR_LIFECYCLE_PROP_NAME = "name"; //$NON-NLS-1$
+
+ private static final String ATTR_LIFECYCLE_PROP_ID = "id"; //$NON-NLS-1$
+
+ private static final String ELEMENT_LIFECYCLE_MAPPING_PROPERTY_PAGE = "lifecycleMappingPropertyPage"; //$NON-NLS-1$
+
+ private static LifecycleMappingPropertyPageFactory factory;
+
+ private Map<String, ILifecyclePropertyPage> pageMap;
+
+ public static LifecycleMappingPropertyPageFactory getFactory() {
+ if(factory == null) {
+ factory = new LifecycleMappingPropertyPageFactory();
+ factory.buildFactory();
+ }
+ return factory;
+ }
+
+ /**
+ * Get a particular lifecycle property page, set in the project to use for the lifecycle mapping, set the Shell for
+ * displaying dialogs.
+ *
+ * @param id
+ * @param project
+ * @param shell
+ * @return
+ */
+ public ILifecyclePropertyPage getPageForId(String id, IProject project, Shell shell) {
+ if(id == null){
+ //for the no-op (empty) lifecycle mapping, use that page
+ id = "NULL"; //$NON-NLS-1$
+ }
+ ILifecyclePropertyPage page = getFactory().pageMap.get(id);
+ if(page == null){
+ return null;
+ }
+ page.setProject(project);
+ page.setShell(shell);
+ return page;
+ }
+
+ public ILifecyclePropertyPage getPage(String id){
+ return getFactory().pageMap.get(id);
+ }
+
+ public void buildFactory() {
+ pageMap = new HashMap<String, ILifecyclePropertyPage>();
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint configuratorsExtensionPoint = registry.getExtensionPoint(EXTENSION_LIFECYCLE_MAPPING_PROPERTY_PAGE);
+ if(configuratorsExtensionPoint != null) {
+ IExtension[] configuratorExtensions = configuratorsExtensionPoint.getExtensions();
+ for(IExtension extension : configuratorExtensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for(IConfigurationElement element : elements) {
+ if(element.getName().equals(ELEMENT_LIFECYCLE_MAPPING_PROPERTY_PAGE)) {
+ try {
+ Object o = element.createExecutableExtension("class"); //$NON-NLS-1$
+ ILifecyclePropertyPage propPage = (ILifecyclePropertyPage) o;
+ String id = element.getAttribute(ATTR_LIFECYCLE_MAPPING_ID);
+
+ propPage.setLifecycleMappingId(id);
+ String name = element.getAttribute(ATTR_LIFECYCLE_PROP_NAME);
+ propPage.setName(name);
+
+ String pageId = element.getAttribute(ATTR_LIFECYCLE_PROP_ID);
+ if(pageId != null) {
+ propPage.setPageId(pageId);
+ }
+ pageMap.put(id, propPage);
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static IMavenProjectFacade getProjectFacade(IProject project) {
+ MavenProjectManager projectManager = MavenPlugin.getDefault().getMavenProjectManager();
+ return projectManager.create(project, new NullProgressMonitor());
+ }
+
+ public static ResolverConfiguration getResolverConfiguration(IProject project) {
+ MavenProjectManager projectManager = MavenPlugin.getDefault().getMavenProjectManager();
+ return projectManager.getResolverConfiguration(project);
+ }
+
+ public static ILifecycleMapping getLifecycleMapping(IProject project) throws CoreException {
+ IMavenProjectFacade facade = getProjectFacade(project);
+ ILifecycleMapping lifecycleMapping = null;
+ IProjectConfigurationManager configurationManager = MavenPlugin.getDefault().getProjectConfigurationManager();
+ lifecycleMapping = configurationManager.getLifecycleMapping(facade, new NullProgressMonitor());
+ return lifecycleMapping;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTable.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTable.java
new file mode 100644
index 00000000..806aeebb
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTable.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.lifecycle;
+
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator;
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+
+/**
+ * ProjectConfiguratorsTable
+ * Composite that holds a read only table of project configurators for a given lifecycle mapping strategy.
+ *
+ * @author dyocum
+ */
+public class ProjectConfiguratorsTable {
+
+ private TableViewer configuratorsTable;
+ private ProjectConfiguratorsTableContentProvider configuratorsContentProvider;
+ private ProjectConfiguratorsTableLabelProvider configuratorsLabelProvider;
+ public static final String[] CONFIG_TABLE_COLUMN_PROPERTIES = new String[]{ "name", "id"}; //$NON-NLS-1$ //$NON-NLS-2$
+ public static final String[] CONFIG_TABLE_COLUMN_NAMES = new String[]{ Messages.ProjectConfiguratorsTable_column_name, Messages.ProjectConfiguratorsTable_column_id};
+ private static final int TABLE_WIDTH = 500;
+
+ public ProjectConfiguratorsTable(Composite parent, IProject project){
+ createTable(parent);
+ updateTable(project);
+ }
+
+ protected void updateTable(IProject project){
+ if(project != null){
+ try{
+ ILifecycleMapping mapping = LifecycleMappingPropertyPageFactory.getLifecycleMapping(project);
+ List<AbstractProjectConfigurator> projectConfigurators = mapping.getProjectConfigurators(LifecycleMappingPropertyPageFactory.getProjectFacade(project), new NullProgressMonitor());
+ setProjectConfigurators(projectConfigurators.toArray(new AbstractProjectConfigurator[]{}));
+ } catch(CoreException e){
+ setProjectConfigurators(new AbstractProjectConfigurator[]{});
+ }
+ }
+ }
+ private void createTable(Composite parent){
+ configuratorsTable = new TableViewer(parent, SWT.BORDER|SWT.H_SCROLL|SWT.V_SCROLL);
+ TableViewerColumn nameColumn = new TableViewerColumn(configuratorsTable, SWT.LEFT);
+ nameColumn.getColumn().setText(CONFIG_TABLE_COLUMN_NAMES[0]);
+ nameColumn.getColumn().setWidth((int)(TABLE_WIDTH*.50));
+
+ TableViewerColumn idColumn = new TableViewerColumn(configuratorsTable, SWT.LEFT);
+ idColumn.getColumn().setText(CONFIG_TABLE_COLUMN_NAMES[1]);
+ idColumn.getColumn().setWidth((int)(TABLE_WIDTH*.50));
+
+ configuratorsTable.getTable().setHeaderVisible(true);
+ configuratorsTable.getTable().setLinesVisible(true);
+ configuratorsContentProvider = new ProjectConfiguratorsTableContentProvider();
+ configuratorsLabelProvider = new ProjectConfiguratorsTableLabelProvider();
+ configuratorsTable.setContentProvider(configuratorsContentProvider);
+ configuratorsTable.setLabelProvider(configuratorsLabelProvider);
+ configuratorsTable.setColumnProperties(CONFIG_TABLE_COLUMN_PROPERTIES);
+ configuratorsTable.getTable().setData("name", "projectConfiguratorsTable"); //$NON-NLS-1$ //$NON-NLS-2$
+ GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1);
+ gd.horizontalIndent=6;
+ gd.grabExcessHorizontalSpace = true;
+ gd.grabExcessVerticalSpace = true;
+ configuratorsTable.getControl().setLayoutData(gd);
+
+ final TableColumn nCol = nameColumn.getColumn();
+ final TableColumn iCol = idColumn.getColumn();
+ final Table tab = configuratorsTable.getTable();
+ configuratorsTable.getTable().addControlListener(new ControlAdapter() {
+ public void controlResized(ControlEvent e) {
+ nCol.setWidth((int)(tab.getClientArea().width*0.50));
+ iCol.setWidth((int)(tab.getClientArea().width*0.50));
+ }
+ });
+ }
+
+ public TableViewer getTableViewer(){
+ return configuratorsTable;
+ }
+
+ public void setProjectConfigurators(AbstractProjectConfigurator[] configurators){
+ configuratorsTable.setInput(configurators);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTableContentProvider.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTableContentProvider.java
new file mode 100644
index 00000000..72fb20ac
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTableContentProvider.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.lifecycle;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator;
+
+/**
+ * ConfiguratorsTableContentProvider
+ *
+ * @author dyocum
+ */
+public class ProjectConfiguratorsTableContentProvider implements IStructuredContentProvider {
+
+ public ProjectConfiguratorsTableContentProvider(){
+ }
+
+ protected String[] getNoConfigMsg(){
+ return new String[]{Messages.ProjectConfiguratorsTableContentProvider_no_configs};
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
+ */
+ public Object[] getElements(Object inputElement) {
+
+ if(inputElement == null || !(inputElement instanceof AbstractProjectConfigurator[]) || ((AbstractProjectConfigurator[])inputElement).length == 0){
+ return getNoConfigMsg();
+ }
+ return (AbstractProjectConfigurator[])inputElement;
+
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+ */
+ public void dispose() {
+ // TODO Auto-generated method dispose
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
+ */
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // TODO Auto-generated method inputChanged
+
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTableLabelProvider.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTableLabelProvider.java
new file mode 100644
index 00000000..92fee588
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/lifecycle/ProjectConfiguratorsTableLabelProvider.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.lifecycle;
+
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator;
+
+/**
+ * ConfiguratorsTableLabelProvider
+ *
+ * @author dyocum
+ */
+public class ProjectConfiguratorsTableLabelProvider implements ITableLabelProvider, IColorProvider{
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
+ */
+ public Image getColumnImage(Object element, int columnIndex) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
+ */
+ public String getColumnText(Object element, int columnIndex) {
+ if(element == null){
+ return ""; //$NON-NLS-1$
+ } else if(element instanceof AbstractProjectConfigurator){
+ return columnIndex == 0 ? ((AbstractProjectConfigurator)element).getName() : ((AbstractProjectConfigurator)element).getId();
+ }
+ return columnIndex == 0 ? element.toString() : ""; //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
+ */
+ public void addListener(ILabelProviderListener listener) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
+ */
+ public void dispose() {
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
+ */
+ public boolean isLabelProperty(Object element, String property) {
+ // TODO Auto-generated method isLabelProperty
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
+ */
+ public void removeListener(ILabelProviderListener listener) {
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object)
+ */
+ public Color getBackground(Object element) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object)
+ */
+ public Color getForeground(Object element) {
+ if(element instanceof AbstractProjectConfigurator){
+ return Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ }
+ return Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY);
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/CustomizableLifecycleMappingPropertyPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/CustomizableLifecycleMappingPropertyPage.java
new file mode 100644
index 00000000..7f714460
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/CustomizableLifecycleMappingPropertyPage.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.ui.internal.lifecycle.AbstractLifecyclePropertyPage;
+import org.eclipse.m2e.core.ui.internal.lifecycle.ProjectConfiguratorsTable;
+
+/**
+ * CustomizableLifecycleMappingPropertyPage
+ *
+ * @author dyocum
+ */
+public class CustomizableLifecycleMappingPropertyPage extends AbstractLifecyclePropertyPage{
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
+ */
+ public Control createContents(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+ composite.setLayoutData(new GridData(GridData.FILL));
+ new ProjectConfiguratorsTable(composite, getProject());
+ return composite;
+ }
+
+ public void performDefaults(){
+ //do nothing
+ }
+
+ public boolean performOk() {
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.lifecycle.AbstractLifecyclePropertyPage#getMessage()
+ */
+ public String getMessage() {
+ // TODO Auto-generated method getMessage
+ return Messages.CustomizableLifecycleMappingPropertyPage_message;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/EmptyLifecycleMappingPropertyPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/EmptyLifecycleMappingPropertyPage.java
new file mode 100644
index 00000000..92c98101
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/EmptyLifecycleMappingPropertyPage.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * EmptyLifecycleMappingPropertyPage
+ *
+ * @author dyocum
+ */
+public class EmptyLifecycleMappingPropertyPage extends SimpleLifecycleMappingPropertyPage {
+
+ public EmptyLifecycleMappingPropertyPage() {
+ super(Messages.EmptyLifecycleMappingPropertyPage_title);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/GoalsFieldEditor.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/GoalsFieldEditor.java
new file mode 100644
index 00000000..480f0dad
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/GoalsFieldEditor.java
@@ -0,0 +1,196 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+
+
+/**
+ * A field editor for a combo box that allows the drop-down selection of one of
+ * a list of items.
+ *
+ * Adapted from org.eclipse.jface.preference.ComboFieldEditor
+ */
+public class GoalsFieldEditor extends FieldEditor {
+
+ /**
+ * The <code>Combo</code> widget.
+ */
+ Text goalsText;
+
+ /**
+ * The value (not the name) of the currently selected item in the Combo widget.
+ */
+ String value;
+
+ private Button goialsSelectButton;
+
+ private final String buttonText;
+
+ /**
+ * Create the combo box field editor.
+ *
+ * @param name the name of the preference this field editor works on
+ * @param labelText the label text of the field editor
+ * @param buttonText
+ * @param entryValues the entry values
+ * @param parent the parent composite
+ */
+ public GoalsFieldEditor(String name, String labelText, String buttonText, Composite parent) {
+ init(name, labelText);
+ this.buttonText = buttonText;
+ createControl(parent);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.FieldEditor#adjustForNumColumns(int)
+ */
+ protected void adjustForNumColumns(int numColumns) {
+ if(numColumns > 1) {
+ Control control = getLabelControl();
+ ((GridData) control.getLayoutData()).horizontalSpan = numColumns;
+ ((GridData) goalsText.getLayoutData()).horizontalSpan = numColumns - 1;
+ } else {
+ Control control = getLabelControl();
+ ((GridData) control.getLayoutData()).horizontalSpan = 2;
+ ((GridData) goalsText.getLayoutData()).horizontalSpan = 1;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.FieldEditor#doFillIntoGrid(org.eclipse.swt.widgets.Composite, int)
+ */
+ protected void doFillIntoGrid(Composite parent, int numColumns) {
+ Control labelControl = getLabelControl(parent);
+ GridData gd = new GridData();
+ gd.horizontalSpan = numColumns;
+ gd.horizontalAlignment = GridData.FILL;
+ gd.grabExcessHorizontalSpace = true;
+ labelControl.setLayoutData(gd);
+
+ Text goalsText = getTextControl(parent);
+ gd = new GridData();
+ gd.horizontalSpan = numColumns - 1;
+ gd.horizontalAlignment = GridData.FILL;
+ gd.grabExcessHorizontalSpace = true;
+ goalsText.setLayoutData(gd);
+ goalsText.setFont(parent.getFont());
+
+ goialsSelectButton = new Button(parent, SWT.NONE);
+ goialsSelectButton.setText(buttonText);
+ goialsSelectButton.addSelectionListener(new MavenGoalSelectionAdapter(goalsText, parent.getShell()));
+ gd = new GridData();
+ gd.horizontalSpan = 1;
+ gd.horizontalAlignment = GridData.FILL;
+ gd.grabExcessHorizontalSpace = true;
+ goalsText.setLayoutData(gd);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.FieldEditor#doLoad()
+ */
+ protected void doLoad() {
+ updateComboForValue(getPreferenceStore().getString(getPreferenceName()));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.FieldEditor#doLoadDefault()
+ */
+ protected void doLoadDefault() {
+ updateComboForValue(getPreferenceStore().getDefaultString(getPreferenceName()));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.FieldEditor#doStore()
+ */
+ protected void doStore() {
+ if (value == null) {
+ getPreferenceStore().setToDefault(getPreferenceName());
+ } else {
+ getPreferenceStore().setValue(getPreferenceName(), value);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.FieldEditor#getNumberOfControls()
+ */
+ public int getNumberOfControls() {
+ return 2;
+ }
+
+ /*
+ * Lazily create and return the Combo control.
+ */
+ private Text getTextControl(Composite parent) {
+ if (goalsText == null) {
+ goalsText = new Text(parent, SWT.BORDER);
+ goalsText.setFont(parent.getFont());
+// for (int i = 0; i < entryValues.length; i++) {
+// goalsCombo.add(entryValues[i], i);
+// }
+// goalsCombo.addSelectionListener(new SelectionAdapter() {
+// public void widgetSelected(SelectionEvent evt) {
+// String oldValue = value;
+// value = goalsCombo.getText();
+// setPresentsDefaultValue(false);
+// fireValueChanged(VALUE, oldValue, value);
+// }
+// });
+ goalsText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent modifyevent) {
+ String oldValue = value;
+ value = goalsText.getText();
+ setPresentsDefaultValue(false);
+ fireValueChanged(VALUE, oldValue, value);
+ }
+ });
+ }
+ return goalsText;
+ }
+
+ protected void setPresentsDefaultValue(boolean booleanValue) {
+ super.setPresentsDefaultValue(booleanValue);
+ }
+
+ protected void fireValueChanged(String property, Object oldValue, Object newValue) {
+ super.fireValueChanged(property, oldValue, newValue);
+ }
+
+// /*
+// * Given the name (label) of an entry, return the corresponding value.
+// */
+// String getValueForName(String name) {
+// for (int i = 0; i < fEntryValues.length; i++) {
+// String[] entry = fEntryValues[i];
+// if (name.equals(entry[0])) {
+// return entry[1];
+// }
+// }
+// return fEntryValues[0][0];
+// }
+
+ /*
+ * Set the name in the combo widget to match the specified value.
+ */
+ private void updateComboForValue(String value) {
+ this.value = value;
+ goalsText.setText(value);
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/LocalArchetypeCatalogDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/LocalArchetypeCatalogDialog.java
new file mode 100644
index 00000000..52c49d57
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/LocalArchetypeCatalogDialog.java
@@ -0,0 +1,230 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import org.apache.maven.archetype.catalog.Archetype;
+import org.apache.maven.archetype.catalog.ArchetypeCatalog;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory;
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory.LocalCatalogFactory;
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * Local Archetype catalog dialog
+ *
+ * @author Eugene Kuleshov
+ */
+public class LocalArchetypeCatalogDialog extends TitleAreaDialog {
+
+ private static final String DIALOG_SETTINGS = LocalArchetypeCatalogDialog.class.getName();
+
+ private static final String KEY_LOCATIONS = "catalogLocation"; //$NON-NLS-1$
+
+ private static final int MAX_HISTORY = 15;
+
+ private String title;
+
+ private String message;
+
+ Combo catalogLocationCombo;
+
+ private Text catalogDescriptionText;
+
+ private IDialogSettings dialogSettings;
+
+ private ArchetypeCatalogFactory archetypeCatalogFactory;
+
+
+ protected LocalArchetypeCatalogDialog(Shell shell, ArchetypeCatalogFactory factory) {
+ super(shell);
+ this.archetypeCatalogFactory = factory;
+ this.title = Messages.LocalArchetypeCatalogDialog_title;
+ this.message = Messages.LocalArchetypeCatalogDialog_message;
+ setShellStyle(SWT.DIALOG_TRIM);
+
+ IDialogSettings pluginSettings = MavenPlugin.getDefault().getDialogSettings();
+ dialogSettings = pluginSettings.getSection(DIALOG_SETTINGS);
+ if(dialogSettings == null) {
+ dialogSettings = new DialogSettings(DIALOG_SETTINGS);
+ pluginSettings.addSection(dialogSettings);
+ }
+ }
+
+ protected Control createContents(Composite parent) {
+ Control control = super.createContents(parent);
+ setTitle(title);
+ setMessage(message);
+ return control;
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite composite1 = (Composite) super.createDialogArea(parent);
+
+ Composite composite = new Composite(composite1, SWT.NONE);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.marginTop = 7;
+ gridLayout.marginWidth = 12;
+ gridLayout.numColumns = 3;
+ composite.setLayout(gridLayout);
+
+ Label catalogLocationLabel = new Label(composite, SWT.NONE);
+ catalogLocationLabel.setText(Messages.LocalArchetypeCatalogDialog_lblCatalog);
+
+ catalogLocationCombo = new Combo(composite, SWT.NONE);
+ GridData gd_catalogLocationCombo = new GridData(SWT.FILL, SWT.CENTER, true, false);
+ gd_catalogLocationCombo.widthHint = 250;
+ catalogLocationCombo.setLayoutData(gd_catalogLocationCombo);
+ catalogLocationCombo.setItems(getSavedValues(KEY_LOCATIONS));
+
+ Button browseButton = new Button(composite, SWT.NONE);
+ browseButton.setText(Messages.LocalArchetypeCatalogDialog_btnBrowse);
+ browseButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ FileDialog dialog = new FileDialog(getShell());
+ dialog.setText(Messages.LocalArchetypeCatalogDialog_dialog_title);
+ String location = dialog.open();
+ if(location!=null) {
+ catalogLocationCombo.setText(location);
+ update();
+ }
+ }
+ });
+ setButtonLayoutData(browseButton);
+
+ Label catalogDescriptionLabel = new Label(composite, SWT.NONE);
+ catalogDescriptionLabel.setText(Messages.LocalArchetypeCatalogDialog_lblDesc);
+
+ catalogDescriptionText = new Text(composite, SWT.BORDER);
+ catalogDescriptionText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+
+ if(archetypeCatalogFactory!=null) {
+ catalogLocationCombo.setText(archetypeCatalogFactory.getId());
+ catalogDescriptionText.setText(archetypeCatalogFactory.getDescription());
+ }
+
+ ModifyListener modifyListener = new ModifyListener() {
+ public void modifyText(final ModifyEvent e) {
+ update();
+ }
+ };
+ catalogLocationCombo.addModifyListener(modifyListener);
+ catalogDescriptionText.addModifyListener(modifyListener);
+
+ return composite;
+ }
+
+ private String[] getSavedValues(String key) {
+ String[] array = dialogSettings.getArray(key);
+ return array == null ? new String[0] : array;
+ }
+
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ shell.setText(title);
+ }
+
+ public void create() {
+ super.create();
+ getButton(IDialogConstants.OK_ID).setEnabled(false);
+ }
+
+ protected void okPressed() {
+ String description = catalogDescriptionText.getText().trim();
+ String location = catalogLocationCombo.getText().trim();
+
+ archetypeCatalogFactory = new LocalCatalogFactory(location, description, true);
+
+ saveValue(KEY_LOCATIONS, location);
+
+ super.okPressed();
+ }
+
+ public ArchetypeCatalogFactory getArchetypeCatalogFactory() {
+ return archetypeCatalogFactory;
+ }
+
+ private void saveValue(String key, String value) {
+ List<String> dirs = new ArrayList<String>();
+ dirs.addAll(Arrays.asList(getSavedValues(key)));
+
+ dirs.remove(value);
+ dirs.add(0, value);
+
+ if(dirs.size() > MAX_HISTORY) {
+ dirs = dirs.subList(0, MAX_HISTORY);
+ }
+
+ dialogSettings.put(key, dirs.toArray(new String[dirs.size()]));
+ }
+
+ void update() {
+ boolean isValid = isValid();
+ // verifyButton.setEnabled(isValid);
+ getButton(IDialogConstants.OK_ID).setEnabled(isValid);
+ }
+
+ private boolean isValid() {
+ setErrorMessage(null);
+ setMessage(null, IStatus.WARNING);
+
+ String location = catalogLocationCombo.getText().trim();
+ if(location.length()==0) {
+ setErrorMessage(Messages.LocalArchetypeCatalogDialog_error_no_location);
+ return false;
+ }
+
+ if(!new File(location).exists()) {
+ setErrorMessage(Messages.LocalArchetypeCatalogDialog_error_exist);
+ return false;
+ }
+
+ LocalCatalogFactory factory = new LocalCatalogFactory(location, null, true);
+ ArchetypeCatalog archetypeCatalog = factory.getArchetypeCatalog();
+ @SuppressWarnings("unchecked")
+ List<Archetype> archetypes = archetypeCatalog.getArchetypes();
+ if(archetypes==null || archetypes.size()==0) {
+ setMessage(Messages.LocalArchetypeCatalogDialog_error_empty, IStatus.WARNING);
+ }
+
+ return true;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenArchetypesPreferencePage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenArchetypesPreferencePage.java
new file mode 100644
index 00000000..18b4f125
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenArchetypesPreferencePage.java
@@ -0,0 +1,320 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.IWebBrowser;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory;
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory.LocalCatalogFactory;
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory.RemoteCatalogFactory;
+import org.eclipse.m2e.core.archetype.ArchetypeManager;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * Maven Archetype catalogs preference page
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenArchetypesPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
+
+ ArchetypeManager archetypeManager;
+ TableViewer archetypesViewer;
+
+ List<ArchetypeCatalogFactory> archetypeCatalogs;
+
+ public MavenArchetypesPreferencePage() {
+ setTitle(Messages.MavenArchetypesPreferencePage_title);
+
+ this.archetypeManager = MavenPlugin.getDefault().getArchetypeManager();
+ }
+
+ protected void performDefaults() {
+ for(Iterator<ArchetypeCatalogFactory> it = archetypeCatalogs.iterator(); it.hasNext();) {
+ ArchetypeCatalogFactory factory = it.next();
+ if(factory.isEditable()) {
+ it.remove();
+ }
+ }
+
+ archetypesViewer.setInput(archetypeCatalogs);
+ archetypesViewer.setSelection(null, true);
+
+ super.performDefaults();
+ }
+
+ public boolean performOk() {
+ Collection<ArchetypeCatalogFactory> catalogs = archetypeManager.getArchetypeCatalogs();
+ for(ArchetypeCatalogFactory factory : catalogs) {
+ if(factory.isEditable()) {
+ archetypeManager.removeArchetypeCatalogFactory(factory.getId());
+ }
+ }
+ for(ArchetypeCatalogFactory factory : archetypeCatalogs) {
+ if(factory.isEditable()) {
+ archetypeManager.addArchetypeCatalogFactory(factory);
+ }
+ }
+
+ try {
+ archetypeManager.saveCatalogs();
+ } catch(IOException ex) {
+ setErrorMessage(NLS.bind(Messages.MavenArchetypesPreferencePage_error, ex.getMessage()));
+ return false;
+ }
+
+ return super.performOk();
+ }
+
+ public void init(IWorkbench workbench) {
+ }
+
+ protected Control createContents(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout(2, false);
+ gridLayout.marginWidth = 0;
+ gridLayout.marginHeight = 0;
+ composite.setLayout(gridLayout);
+
+ Link addRemoveOrLink = new Link(composite, SWT.NONE);
+ GridData gd_addRemoveOrLink = new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1);
+ addRemoveOrLink.setLayoutData(gd_addRemoveOrLink);
+ addRemoveOrLink.setText(Messages.MavenArchetypesPreferencePage_link);
+ addRemoveOrLink.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ try {
+ URL url = new URL("http://maven.apache.org/plugins/maven-archetype-plugin/specification/archetype-catalog.html"); //$NON-NLS-1$
+ IWebBrowser browser = PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser();
+ browser.openURL(url);
+ } catch(MalformedURLException ex) {
+ MavenLogger.log("Malformed URL", ex);
+ } catch(PartInitException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ });
+
+ // archetypesViewer = CheckboxTableViewer.newCheckList(composite, SWT.BORDER | SWT.FULL_SELECTION);
+ archetypesViewer = new TableViewer(composite, SWT.BORDER | SWT.FULL_SELECTION);
+
+ archetypesViewer.setLabelProvider(new CatalogsLabelProvider());
+
+ archetypesViewer.setContentProvider(new IStructuredContentProvider() {
+
+ public Object[] getElements(Object input) {
+ if(input instanceof Collection) {
+ return ((Collection<?>) input).toArray();
+ }
+ return new Object[0];
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ public void dispose() {
+ }
+
+ });
+
+ Table table = archetypesViewer.getTable();
+ table.setLinesVisible(false);
+ table.setHeaderVisible(false);
+ table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 4));
+
+ TableColumn typeColumn = new TableColumn(table, SWT.NONE);
+ typeColumn.setWidth(250);
+ typeColumn.setText(""); //$NON-NLS-1$
+
+ Button addLocalButton = new Button(composite, SWT.NONE);
+ addLocalButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ addLocalButton.setText(Messages.MavenArchetypesPreferencePage_btnAddLocal);
+ addLocalButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ LocalArchetypeCatalogDialog dialog = new LocalArchetypeCatalogDialog(getShell(), null);
+ if (dialog.open()==Window.OK) {
+ ArchetypeCatalogFactory factory = dialog.getArchetypeCatalogFactory();
+ archetypeCatalogs.add(factory);
+ archetypesViewer.setInput(archetypeCatalogs);
+ archetypesViewer.setSelection(new StructuredSelection(factory), true);
+ }
+ }
+ });
+
+ Button addRemoteButton = new Button(composite, SWT.NONE);
+ addRemoteButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ addRemoteButton.setText(Messages.MavenArchetypesPreferencePage_btnAddRemote);
+ addRemoteButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ RemoteArchetypeCatalogDialog dialog = new RemoteArchetypeCatalogDialog(getShell(), null);
+ if (dialog.open()==Window.OK) {
+ ArchetypeCatalogFactory factory = dialog.getArchetypeCatalogFactory();
+ archetypeCatalogs.add(factory);
+ archetypesViewer.setInput(archetypeCatalogs);
+ archetypesViewer.setSelection(new StructuredSelection(factory), true);
+ }
+ }
+ });
+
+ final Button editButton = new Button(composite, SWT.NONE);
+ editButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ editButton.setEnabled(false);
+ editButton.setText(Messages.MavenArchetypesPreferencePage_btnEdit);
+ editButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ ArchetypeCatalogFactory factory = getSelectedArchetypeCatalogFactory();
+ ArchetypeCatalogFactory newFactory = null;
+ if(factory instanceof LocalCatalogFactory) {
+ LocalArchetypeCatalogDialog dialog = new LocalArchetypeCatalogDialog(getShell(), factory);
+ if (dialog.open()==Window.OK) {
+ newFactory = dialog.getArchetypeCatalogFactory();
+ }
+ } else if(factory instanceof RemoteCatalogFactory) {
+ RemoteArchetypeCatalogDialog dialog = new RemoteArchetypeCatalogDialog(getShell(), factory);
+ if (dialog.open()==Window.OK) {
+ newFactory = dialog.getArchetypeCatalogFactory();
+ }
+ }
+ if(newFactory!=null) {
+ int n = archetypeCatalogs.indexOf(factory);
+ if(n>-1) {
+ archetypeCatalogs.set(n, newFactory);
+ archetypesViewer.setInput(archetypeCatalogs);
+ archetypesViewer.setSelection(new StructuredSelection(newFactory), true);
+ }
+ }
+ }
+ });
+
+ final Button removeButton = new Button(composite, SWT.NONE);
+ removeButton.setEnabled(false);
+ removeButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, true));
+ removeButton.setText(Messages.MavenArchetypesPreferencePage_btnRemove);
+ removeButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ ArchetypeCatalogFactory factory = getSelectedArchetypeCatalogFactory();
+ archetypeCatalogs.remove(factory);
+ archetypesViewer.setInput(archetypeCatalogs);
+ archetypesViewer.setSelection(null, true);
+ }
+ });
+
+ archetypesViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ if(archetypesViewer.getSelection() instanceof IStructuredSelection) {
+ ArchetypeCatalogFactory factory = getSelectedArchetypeCatalogFactory();
+ boolean isEnabled = factory != null && factory.isEditable();
+ removeButton.setEnabled(isEnabled);
+ editButton.setEnabled(isEnabled);
+ }
+ }
+ });
+
+ archetypeCatalogs = new ArrayList<ArchetypeCatalogFactory>(archetypeManager.getArchetypeCatalogs());
+ archetypesViewer.setInput(archetypeCatalogs);
+ archetypesViewer.refresh(); // should listen on property changes instead?
+
+ return composite;
+ }
+
+ protected ArchetypeCatalogFactory getSelectedArchetypeCatalogFactory() {
+ IStructuredSelection selection = (IStructuredSelection) archetypesViewer.getSelection();
+ return (ArchetypeCatalogFactory) selection.getFirstElement();
+ }
+
+
+ static class CatalogsLabelProvider implements ITableLabelProvider, IColorProvider {
+
+ private Color disabledColor = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY);
+
+ public String getColumnText(Object element, int columnIndex) {
+ ArchetypeCatalogFactory factory = (ArchetypeCatalogFactory) element;
+ if(factory instanceof LocalCatalogFactory) {
+ return NLS.bind(Messages.MavenArchetypesPreferencePage_local, factory.getDescription());
+ } else if(factory instanceof RemoteCatalogFactory) {
+ if(factory.isEditable()) {
+ return NLS.bind(Messages.MavenArchetypesPreferencePage_remote,factory.getDescription());
+ }
+ return NLS.bind(Messages.MavenArchetypesPreferencePage_packaged, factory.getDescription());
+ }
+ return factory.getDescription();
+ }
+
+ public Image getColumnImage(Object element, int columnIndex) {
+ return null;
+ }
+
+ public Color getBackground(Object element) {
+ return null;
+ }
+
+ public Color getForeground(Object element) {
+ ArchetypeCatalogFactory factory = (ArchetypeCatalogFactory) element;
+ return !factory.isEditable() ? disabledColor : null;
+ }
+
+ public void dispose() {
+ }
+
+ public boolean isLabelProperty(Object element, String property) {
+ return false;
+ }
+
+ public void addListener(ILabelProviderListener listener) {
+ }
+
+ public void removeListener(ILabelProviderListener listener) {
+ }
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenGoalSelectionAdapter.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenGoalSelectionAdapter.java
new file mode 100644
index 00000000..25493b14
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenGoalSelectionAdapter.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import org.eclipse.m2e.core.ui.dialogs.MavenGoalSelectionDialog;
+
+public class MavenGoalSelectionAdapter extends SelectionAdapter {
+ private Shell shell;
+ private Text text;
+
+ public MavenGoalSelectionAdapter(Text text, Shell shell) {
+ this.text = text;
+ this.shell = shell;
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+// String fileName = Util.substituteVar(fPomDirName.getText());
+// if(!isDirectoryExist(fileName)) {
+// MessageDialog.openError(getShell(), Messages.getString("launch.errorPomMissing"),
+// Messages.getString("launch.errorSelectPom")); //$NON-NLS-1$ //$NON-NLS-2$
+// return;
+// }
+ MavenGoalSelectionDialog dialog = new MavenGoalSelectionDialog(shell);
+ int rc = dialog.open();
+ if(rc == IDialogConstants.OK_ID) {
+ text.insert(""); // clear selected text //$NON-NLS-1$
+
+ String txt = text.getText();
+ int len = txt.length();
+ int pos = text.getCaretPosition();
+
+ StringBuffer sb = new StringBuffer();
+ if((pos > 0 && txt.charAt(pos - 1) != ' ')) {
+ sb.append(' ');
+ }
+
+ String sep = ""; //$NON-NLS-1$
+ Object[] o = dialog.getResult();
+ for(int i = 0; i < o.length; i++ ) {
+ if(o[i] instanceof MavenGoalSelectionDialog.Entry) {
+ if(dialog.isQualifiedName()) {
+ sb.append(sep).append(((MavenGoalSelectionDialog.Entry) o[i]).getQualifiedName());
+ } else {
+ sb.append(sep).append(((MavenGoalSelectionDialog.Entry) o[i]).getName());
+ }
+ }
+ sep = " "; //$NON-NLS-1$
+ }
+
+ if(pos < len && txt.charAt(pos) != ' ') {
+ sb.append(' ');
+ }
+
+ text.insert(sb.toString());
+ text.setFocus();
+ }
+ }
+ } \ No newline at end of file
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenInstallationsPreferencePage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenInstallationsPreferencePage.java
new file mode 100644
index 00000000..e17ffd28
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenInstallationsPreferencePage.java
@@ -0,0 +1,677 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.IWebBrowser;
+import org.eclipse.ui.ide.IDE;
+
+import org.apache.maven.settings.building.SettingsProblem;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.embedder.MavenRuntime;
+import org.eclipse.m2e.core.embedder.MavenRuntimeManager;
+import org.eclipse.m2e.core.index.IndexManager;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.embedder.MavenEmbeddedRuntime;
+import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
+
+
+/**
+ * Maven installations preference page
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenInstallationsPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
+
+ final MavenPlugin mavenPlugin;
+
+ final MavenRuntimeManager runtimeManager;
+
+ final IMavenConfiguration mavenConfiguration;
+
+ final IMaven maven;
+
+ MavenRuntime defaultRuntime;
+
+ List<MavenRuntime> runtimes;
+
+ CheckboxTableViewer runtimesViewer;
+
+ Text globalSettingsText;
+
+ private String globalSettings;
+
+ boolean dirty = false;
+
+ public MavenInstallationsPreferencePage() {
+ setTitle(Messages.MavenInstallationsPreferencePage_title);
+
+ this.mavenPlugin = MavenPlugin.getDefault();
+ this.runtimeManager = mavenPlugin.getMavenRuntimeManager();
+ this.mavenConfiguration = MavenPlugin.getDefault().getMavenConfiguration();
+ this.maven = MavenPlugin.getDefault().getMaven();
+
+ }
+
+ public void init(IWorkbench workbench) {
+ }
+
+ protected void performDefaults() {
+ runtimeManager.reset();
+ defaultRuntime = runtimeManager.getDefaultRuntime();
+ runtimes = runtimeManager.getMavenRuntimes();
+
+ runtimesViewer.setInput(runtimes);
+ runtimesViewer.setChecked(defaultRuntime, true);
+ runtimesViewer.refresh();
+
+ storeCustom(""); //$NON-NLS-1$
+ globalSettingsText.setText(""); //$NON-NLS-1$
+ mavenConfiguration.setGlobalSettingsFile(""); //$NON-NLS-1$
+
+ updateGlobals(true);
+ super.performDefaults();
+ setDirty(true);
+ }
+
+
+ protected void storeCustom(String dir){
+ mavenPlugin.getPreferenceStore().setValue(P_MAVEN_CUSTOM_GLOBAL, dir == null ? "" : dir); //$NON-NLS-1$
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.PreferencePage#performApply()
+ */
+ protected void performApply() {
+ updateSettings();
+ }
+
+ public void updateSettings(){
+ new Job(Messages.MavenInstallationsPreferencePage_job_updating) {
+ protected IStatus run(IProgressMonitor monitor) {
+ String dir = getGlobalSettingsText();
+
+ runtimeManager.setRuntimes(runtimes);
+ runtimeManager.setDefaultRuntime(defaultRuntime);
+ String oldSettings = mavenConfiguration.getGlobalSettingsFile();
+
+ mavenConfiguration.setGlobalSettingsFile(dir);
+ if(defaultRuntime == null || defaultRuntime instanceof MavenEmbeddedRuntime){
+ storeCustom(dir);
+ }
+ IndexManager indexManager = mavenPlugin.getIndexManager();
+ try {
+ indexManager.getWorkspaceIndex().updateIndex(true, monitor);
+ } catch(CoreException ex) {
+ return ex.getStatus();
+ }
+ if((dir == null && oldSettings != null) || (dir != null && !(dir.equals(oldSettings)))){
+ //mavenPlugin.getIndexManager().scheduleIndexUpdate(IndexManager.LOCAL_INDEX, true, 0L);
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ public boolean performOk() {
+ if (dirty) {
+ updateSettings();
+ }
+ return true;
+ }
+
+ public void setDirty(boolean dirty){
+ this.dirty = dirty;
+ }
+
+ public boolean isDirty(){
+ return this.dirty;
+ }
+
+ protected boolean validateMavenInstall(String dir){
+ if(dir == null || dir.length() == 0){
+ return false;
+ }
+ File selectedDir = new File(dir);
+ if(!selectedDir.isDirectory()){
+ MessageDialog.openError(getShell(), Messages.MavenInstallationsPreferencePage_error_title, Messages.MavenInstallationsPreferencePage_error_message);
+ return false;
+ }
+ File binDir = new File(dir, "bin"); //$NON-NLS-1$
+ File confDir = new File(dir, "conf"); //$NON-NLS-1$
+ File libDir = new File(dir, "lib"); //$NON-NLS-1$
+ if(!binDir.exists() || !confDir.exists() || !libDir.exists()){
+ MessageDialog.openError(getShell(), Messages.MavenInstallationsPreferencePage_error_title, Messages.MavenInstallationsPreferencePage_error2_message);
+ return false;
+ }
+ return true;
+ }
+ protected Control createContents(Composite parent) {
+
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout(3, false);
+ gridLayout.marginBottom = 5;
+ gridLayout.marginRight = 5;
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ composite.setLayout(gridLayout);
+
+ Label link = new Label(composite, SWT.NONE);
+ link.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 3, 1));
+ link.setText(Messages.MavenInstallationsPreferencePage_link);
+
+
+ createTable(composite);
+ createGlobalSettings(composite);
+
+
+ defaultRuntime = runtimeManager.getDefaultRuntime();
+ runtimes = runtimeManager.getMavenRuntimes();
+
+ runtimesViewer.setInput(runtimes);
+ runtimesViewer.setChecked(defaultRuntime, true);
+ runtimesViewer.refresh(); // should listen on property changes instead?
+
+ checkSettings();
+ updateGlobals(false);
+ globalSettingsText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent modifyevent) {
+ setGlobalSettingsText(globalSettingsText.getText());
+ updateGlobalSettingsLink();
+ checkSettings();
+ setDirty(true);
+ }
+ });
+
+ return composite;
+ }
+
+ /**
+ *
+ */
+ private void updateGlobalSettingsText(boolean useLastCustomGlobal) {
+ String globalSettings = getGlobalSettingsFile(useLastCustomGlobal);
+ globalSettingsText.setText(globalSettings == null ? "" : globalSettings); //$NON-NLS-1$
+ }
+
+ /**
+ * Use this to retrieve the global settings file which has not been applied yet
+ * @return
+ */
+ public String getGlobalSettingsFile(boolean useLastCustomGlobal) {
+ if(defaultRuntime == null || defaultRuntime instanceof MavenEmbeddedRuntime){
+ String globalSettings = null;
+ if(useLastCustomGlobal){
+ globalSettings = mavenPlugin.getPreferenceStore().getString(P_MAVEN_CUSTOM_GLOBAL);
+ } else {
+ globalSettings = mavenPlugin.getPreferenceStore().getString(MavenPreferenceConstants.P_GLOBAL_SETTINGS_FILE);
+ }
+ return globalSettings.trim().length()==0 ? null : globalSettings;
+ }
+ return defaultRuntime == null ? null : defaultRuntime.getSettings();
+ }
+
+ public void setGlobalSettingsText(String settings){
+ this.globalSettings = settings;
+ }
+ public String getGlobalSettingsText(){
+ return this.globalSettings;
+ }
+ /**
+ *
+ */
+ private void updateGlobals(boolean useLastCustomGlobal) {
+ updateGlobalSettingsText(useLastCustomGlobal);
+ updateGlobalSettingsLink();
+ updateGlobalSettingsBrowseButton();
+ }
+
+ private Link globalSettingsLink;
+
+ private Button globalSettingsBrowseButton;
+
+ private MavenRuntime getCheckedRuntime(){
+ Object[] runtimes = runtimesViewer.getCheckedElements();
+ if(runtimes != null && runtimes.length > 0){
+ return (MavenRuntime)runtimes[0];
+ }
+ return null;
+ }
+
+ protected MavenRuntime getSelectedMavenRuntime(){
+ IStructuredSelection sel = (IStructuredSelection)runtimesViewer.getSelection();
+ return (MavenRuntime) sel.getFirstElement();
+ }
+
+ private void updateGlobalSettingsLink(){
+ MavenRuntime runtime = getCheckedRuntime();
+ String text = ""; //$NON-NLS-1$
+ String currText = globalSettingsText.getText();
+ boolean showURL = false;
+
+ File f = new File(currText);
+ if(f.exists()){
+ showURL = true;
+ }
+ String openFile = showURL ? Messages.MavenInstallationsPreferencePage_link_open : ":"; //$NON-NLS-2$
+ if(runtime instanceof MavenEmbeddedRuntime){
+ text = Messages.MavenInstallationsPreferencePage_settings+openFile;
+ } else {
+ text = Messages.MavenInstallationsPreferencePage_settings_install+openFile;
+ }
+ globalSettingsLink.setText(text);
+ }
+
+ private void updateGlobalSettingsBrowseButton(){
+ MavenRuntime runtime = getCheckedRuntime();
+ boolean enabled = (runtime != null && (runtime instanceof MavenEmbeddedRuntime));
+ globalSettingsBrowseButton.setEnabled(enabled);
+ globalSettingsText.setEditable(enabled);
+ }
+
+ private void createGlobalSettings(Composite composite) {
+ globalSettingsLink = new Link(composite, SWT.NONE);
+ globalSettingsLink.setData("name", "globalSettingsLink"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ globalSettingsLink.setToolTipText(Messages.MavenInstallationsPreferencePage_link_global);
+ GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1);
+ gd.verticalIndent = 25;
+ globalSettingsLink.setLayoutData(gd);
+
+ globalSettingsLink.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ String globalSettings = getGlobalSettings();
+ if(globalSettings.length() == 0) {
+ globalSettings = defaultRuntime.getSettings();
+ }
+ if(globalSettings != null && globalSettings.length() > 0) {
+ openEditor(globalSettings);
+ }
+ }
+ });
+
+ globalSettingsText = new Text(composite, SWT.BORDER);
+ globalSettingsText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ globalSettingsText.setData("name", "globalSettingsText"); //$NON-NLS-1$ //$NON-NLS-2$
+ globalSettingsBrowseButton = new Button(composite, SWT.NONE);
+ GridData gd_globalSettingsBrowseButton = new GridData(SWT.FILL, SWT.CENTER, false, false);
+ globalSettingsBrowseButton.setLayoutData(gd_globalSettingsBrowseButton);
+ globalSettingsBrowseButton.setText(Messages.MavenInstallationsPreferencePage_btnGlobalBrowse);
+ globalSettingsBrowseButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
+ if(getGlobalSettings().length() > 0) {
+ dialog.setFileName(getGlobalSettings());
+ }
+ String file = dialog.open();
+ if(file != null) {
+ file = file.trim();
+ if(file.length() > 0) {
+ globalSettingsText.setText(file);
+ }
+ }
+ }
+ });
+ }
+
+
+ private void createTable(Composite composite){
+ runtimesViewer = CheckboxTableViewer.newCheckList(composite, SWT.BORDER | SWT.FULL_SELECTION);
+
+ runtimesViewer.setLabelProvider(new RuntimesLabelProvider());
+
+ runtimesViewer.setContentProvider(new IStructuredContentProvider() {
+
+ @SuppressWarnings("unchecked")
+ public Object[] getElements(Object input) {
+ if(input instanceof List) {
+ List list = (List) input;
+ if(list.size() > 0) {
+ return list.toArray(new MavenRuntime[list.size()]);
+ }
+ }
+ return new Object[0];
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ public void dispose() {
+ }
+
+ });
+
+ Table table = runtimesViewer.getTable();
+ table.setLinesVisible(false);
+ table.setHeaderVisible(false);
+ GridData gd_table = new GridData(SWT.FILL, SWT.FILL, true, false, 2, 3);
+ gd_table.heightHint = 151;
+ gd_table.widthHint = 333;
+ table.setLayoutData(gd_table);
+
+ TableColumn typeColumn = new TableColumn(table, SWT.NONE);
+ typeColumn.setWidth(325);
+ typeColumn.setText(""); //$NON-NLS-1$
+
+ Button addButton = new Button(composite, SWT.NONE);
+ addButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ addButton.setText(Messages.MavenInstallationsPreferencePage_btnAdd);
+ addButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ DirectoryDialog dlg = new DirectoryDialog(getShell());
+ dlg.setText(Messages.MavenInstallationsPreferencePage_dialog_install_title);
+ dlg.setMessage(Messages.MavenInstallationsPreferencePage_dialog_install_message);
+ String dir = dlg.open();
+ if(dir == null){
+ return;
+ }
+ boolean ok = validateMavenInstall(dir);
+ if(ok){
+ MavenRuntime runtime = MavenRuntimeManager.createExternalRuntime(dir);
+ if(runtimes.contains(runtime)) {
+ MessageDialog.openError(getShell(), Messages.MavenInstallationsPreferencePage_error_title, Messages.MavenInstallationsPreferencePage_error3_message);
+ } else {
+ runtimes.add(runtime);
+ runtimesViewer.refresh();
+ runtimesViewer.setAllChecked(false);
+ runtimesViewer.setChecked(runtime, true);
+ if(runtime != null){
+ setCheckedRuntime(runtime);
+ }
+ }
+ }
+ }
+ });
+
+ final Button editButton = new Button(composite, SWT.NONE);
+ editButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ editButton.setEnabled(false);
+ editButton.setText(Messages.MavenInstallationsPreferencePage_btnEdit);
+ editButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ MavenRuntime runtime = getSelectedMavenRuntime();
+ DirectoryDialog dlg = new DirectoryDialog(Display.getCurrent().getActiveShell());
+ dlg.setText(Messages.MavenInstallationsPreferencePage_dialog_title);
+ dlg.setMessage(Messages.MavenInstallationsPreferencePage_dialog_message);
+ dlg.setFilterPath(runtime.getLocation());
+ String dir = dlg.open();
+ boolean ok = validateMavenInstall(dir);
+ if(ok && !dir.equals(runtime.getLocation())) {
+ MavenRuntime newRuntime = MavenRuntimeManager.createExternalRuntime(dir);
+ if(runtimes.contains(newRuntime)) {
+ MessageDialog.openError(getShell(), Messages.MavenInstallationsPreferencePage_error_title, Messages.MavenInstallationsPreferencePage_error4_message);
+ } else {
+ runtimes.set(runtimes.indexOf(runtime), newRuntime);
+ runtimesViewer.refresh();
+ setDirty(true);
+ if(newRuntime != null){
+ setCheckedRuntime(newRuntime);
+ }
+ }
+ }
+ }
+ });
+
+ final Button removeButton = new Button(composite, SWT.NONE);
+ removeButton.setEnabled(false);
+ removeButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ removeButton.setText(Messages.MavenInstallationsPreferencePage_btnRemove);
+ removeButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ MavenRuntime runtime = getSelectedMavenRuntime();
+ runtimes.remove(runtime);
+ runtimesViewer.refresh();
+ Object[] checkedElements = runtimesViewer.getCheckedElements();
+ if(checkedElements == null || checkedElements.length == 0) {
+ defaultRuntime = runtimeManager.getRuntime(MavenRuntimeManager.EMBEDDED);
+ runtimesViewer.setChecked(defaultRuntime, true);
+ setCheckedRuntime(defaultRuntime);
+ }
+ setDirty(true);
+ }
+ });
+
+ runtimesViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ if(runtimesViewer.getSelection() instanceof IStructuredSelection) {
+ MavenRuntime runtime = getSelectedMavenRuntime();
+ boolean isEnabled = runtime != null && runtime.isEditable();
+ removeButton.setEnabled(isEnabled);
+ editButton.setEnabled(isEnabled);
+ }
+ }
+ });
+
+ runtimesViewer.addCheckStateListener(new ICheckStateListener() {
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ if(event.getElement() != null && event.getChecked()){
+
+ setCheckedRuntime((MavenRuntime)event.getElement());
+ }
+ }
+ });
+ Link noteLabel = new Link(composite, SWT.WRAP | SWT.READ_ONLY);
+ GridData noteLabelData = new GridData(SWT.FILL, SWT.TOP, false, false, 2, 1);
+ noteLabelData.horizontalIndent = 15;
+ noteLabelData.widthHint = 100;
+
+ noteLabel.setLayoutData(noteLabelData);
+ noteLabel.setText(Messages.MavenInstallationsPreferencePage_lblNote1 +
+ Messages.MavenInstallationsPreferencePage_lblNote2);
+ noteLabel.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ try {
+ URL url = new URL(e.text);
+ IWebBrowser browser = PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser();
+ browser.openURL(url);
+ } catch(MalformedURLException ex) {
+ MavenLogger.log("Malformed URL", ex);
+ } catch(PartInitException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ });
+ }
+
+ private static final String P_MAVEN_CUSTOM_GLOBAL = "customGlobalSettingsFile"; //$NON-NLS-1$
+
+ protected void setCheckedRuntime(MavenRuntime runtime){
+ runtimesViewer.setAllChecked(false);
+ runtimesViewer.setChecked(runtime, true);
+ defaultRuntime = runtime;
+ boolean useDefault = (defaultRuntime == null || defaultRuntime instanceof MavenEmbeddedRuntime);
+ updateGlobals(useDefault);
+ setDirty(true);
+ }
+
+ void checkSettings() {
+ setErrorMessage(null);
+ setMessage(null);
+
+ String globalSettings = getGlobalSettings();
+ if(globalSettings != null && globalSettings.length() > 0) {
+ File globalSettingsFile = new File(globalSettings);
+ if(!globalSettingsFile.exists()) {
+ setMessage(Messages.MavenInstallationsPreferencePage_error_global_missing, IMessageProvider.WARNING);
+ globalSettings = null;
+ }
+ } else {
+ globalSettings = null;
+ }
+
+ List<SettingsProblem> result = maven.validateSettings(globalSettings);
+ if(result.size() > 0) {
+ setMessage(Messages.MavenInstallationsPreferencePage_error_global_parse + result.get(0).getMessage(), IMessageProvider.WARNING);
+ }
+
+ }
+
+
+
+ @SuppressWarnings("unchecked")
+ void openEditor(final String fileName) {
+ // XXX create new settings.xml if does not exist
+
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+ IWorkbenchPage page = window.getActivePage();
+
+ IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor("settings.xml"); //$NON-NLS-1$
+
+ File file = new File(fileName);
+ IEditorInput input = null;
+ try {
+ //class implementing editor input for external file has been renamed in eclipse 3.3, hence reflection
+ Class javaInput = null;
+ try {
+ javaInput = Class.forName("org.eclipse.ui.internal.editors.text.JavaFileEditorInput"); //$NON-NLS-1$
+ Constructor cons = javaInput.getConstructor(new Class[] {File.class});
+ input = (IEditorInput) cons.newInstance(new Object[] {file});
+ } catch(Exception e) {
+ try {
+ IFileStore fileStore = EFS.getLocalFileSystem().fromLocalFile(file);
+ Class storeInput = Class.forName("org.eclipse.ui.ide.FileStoreEditorInput"); //$NON-NLS-1$
+ Constructor cons = storeInput.getConstructor(new Class[] {IFileStore.class});
+ input = (IEditorInput) cons.newInstance(new Object[] {fileStore});
+ } catch(Exception ex) {
+ //ignore...
+ }
+ }
+ final IEditorPart editor = IDE.openEditor(page, input, desc.getId());
+ editor.addPropertyListener(new IPropertyListener() {
+ public void propertyChanged(Object source, int propId) {
+ if(!editor.isDirty()) {
+ mavenPlugin.getConsole().logMessage("Refreshing settings " + fileName);
+ invalidateMavenSettings(false);
+ }
+ }
+ });
+
+ } catch(PartInitException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+
+
+ void invalidateMavenSettings(final boolean reindex) {
+// new Job("Invalidating Maven settings") {
+// protected IStatus run(IProgressMonitor monitor) {
+// mavenPlugin.getMavenEmbedderManager().invalidateMavenSettings();
+// if(reindex) {
+// mavenPlugin.getIndexManager().scheduleIndexUpdate(IndexManager.LOCAL_INDEX, true, 0L);
+// }
+// return Status.OK_STATUS;
+// }
+// }.schedule();
+ }
+ String getGlobalSettings() {
+ return globalSettingsText.getText().trim();
+ }
+
+ static class RuntimesLabelProvider implements ITableLabelProvider, IColorProvider {
+
+ public String getColumnText(Object element, int columnIndex) {
+ MavenRuntime runtime = (MavenRuntime) element;
+ return runtime.toString();
+ }
+
+ public Image getColumnImage(Object element, int columnIndex) {
+ return null;
+ }
+
+ public Color getBackground(Object element) {
+ return null;
+ }
+
+ public Color getForeground(Object element) {
+ MavenRuntime runtime = (MavenRuntime) element;
+ if(!runtime.isEditable()) {
+ return Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY);
+ }
+ return null;
+ }
+
+ public void dispose() {
+ }
+
+ public boolean isLabelProperty(Object element, String property) {
+ return false;
+ }
+
+ public void addListener(ILabelProviderListener listener) {
+ }
+
+ public void removeListener(ILabelProviderListener listener) {
+ }
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenPreferencePage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenPreferencePage.java
new file mode 100644
index 00000000..18105440
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenPreferencePage.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
+
+
+public class MavenPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+ final MavenPlugin plugin;
+
+ public MavenPreferencePage() {
+ super(GRID);
+ setPreferenceStore(MavenPlugin.getDefault().getPreferenceStore());
+
+ plugin = MavenPlugin.getDefault();
+ }
+
+ public void init(IWorkbench workbench) {
+ }
+
+ /*
+ * Creates the field editors. Field editors are abstractions of the common GUI
+ * blocks needed to manipulate various types of preferences. Each field editor
+ * knows how to save and restore itself.
+ */
+ public void createFieldEditors() {
+
+ addField(new BooleanFieldEditor(MavenPreferenceConstants.P_OFFLINE, Messages.getString("preferences.offline"), //$NON-NLS-1$
+ getFieldEditorParent()));
+
+ addField(new BooleanFieldEditor(MavenPreferenceConstants.P_DEBUG_OUTPUT, //
+ Messages.getString("preferences.debugOutput"), //$NON-NLS-1$
+ getFieldEditorParent()));
+
+ // addField( new BooleanFieldEditor( MavenPreferenceConstants.P_UPDATE_SNAPSHOTS,
+ // Messages.getString( "preferences.updateSnapshots" ), //$NON-NLS-1$
+ // getFieldEditorParent() ) );
+
+ addField(new BooleanFieldEditor(MavenPreferenceConstants.P_DOWNLOAD_SOURCES, //
+ Messages.getString("preferences.downloadSources"), //$NON-NLS-1$
+ getFieldEditorParent()));
+
+ addField(new BooleanFieldEditor(MavenPreferenceConstants.P_DOWNLOAD_JAVADOC, //
+ Messages.getString("preferences.downloadJavadoc"), //$NON-NLS-1$
+ getFieldEditorParent()));
+
+ addField(new BooleanFieldEditor(MavenPreferenceConstants.P_UPDATE_INDEXES, //
+ org.eclipse.m2e.core.internal.Messages.MavenPreferencePage_download, //
+ getFieldEditorParent()));
+
+ addField(new BooleanFieldEditor(MavenPreferenceConstants.P_UPDATE_PROJECTS, //
+ org.eclipse.m2e.core.internal.Messages.MavenPreferencePage_update, //
+ getFieldEditorParent()));
+
+ addField(new BooleanFieldEditor(MavenPreferenceConstants.P_HIDE_FOLDERS_OF_NESTED_PROJECTS, //
+ org.eclipse.m2e.core.internal.Messages.MavenPreferencePage_hide, getFieldEditorParent()));
+
+ GridData comboCompositeGridData = new GridData();
+ comboCompositeGridData.verticalIndent = 25;
+ comboCompositeGridData.horizontalSpan = 3;
+ comboCompositeGridData.grabExcessHorizontalSpace = true;
+ comboCompositeGridData.horizontalAlignment = GridData.FILL;
+
+ Composite comboComposite = new Composite(getFieldEditorParent(), SWT.NONE);
+ comboComposite.setLayoutData(comboCompositeGridData);
+ comboComposite.setLayout(new GridLayout(2, false));
+
+ // addSeparator();
+ }
+
+ private void addSeparator() {
+ Label separator = new Label(getFieldEditorParent(), SWT.HORIZONTAL | SWT.SEPARATOR);
+ // separator.setVisible(false);
+ GridData separatorGridData = new GridData();
+ separatorGridData.horizontalSpan = 4;
+ separatorGridData.grabExcessHorizontalSpace = true;
+ separatorGridData.horizontalAlignment = GridData.FILL;
+ separatorGridData.verticalIndent = 10;
+ separator.setLayoutData(separatorGridData);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenProjectLifecycleMappingPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenProjectLifecycleMappingPage.java
new file mode 100644
index 00000000..fca8e44d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenProjectLifecycleMappingPage.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.dialogs.PropertyPage;
+
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+import org.eclipse.m2e.core.ui.internal.lifecycle.ILifecyclePropertyPage;
+import org.eclipse.m2e.core.ui.internal.lifecycle.LifecycleMappingPropertyPageFactory;
+
+/**
+ * Maven project preference page
+ *
+ * @author Dan Yocum
+ */
+public class MavenProjectLifecycleMappingPage extends PropertyPage{
+
+ private ILifecyclePropertyPage currentPage;
+
+ public MavenProjectLifecycleMappingPage() {
+
+ setTitle(""); //$NON-NLS-1$
+ }
+
+ protected Control createContents(Composite parent) {
+ currentPage = loadCurrentPage((IProject)getElement());
+ setMessage(currentPage.getName());
+ return currentPage.createContents(parent);
+ }
+
+ private ILifecyclePropertyPage getErrorPage(String msg){
+ SimpleLifecycleMappingPropertyPage p = new SimpleLifecycleMappingPropertyPage(msg);
+ return p;
+ }
+
+ private ILifecyclePropertyPage getPage(ILifecycleMapping lifecycleMapping){
+ ILifecyclePropertyPage page = LifecycleMappingPropertyPageFactory.getFactory().getPageForId(lifecycleMapping.getId(), getProject(), this.getShell());
+ if(page == null){
+ page = getErrorPage(Messages.MavenProjectLifecycleMappingPage_error_no_page);
+ page.setName(lifecycleMapping.getName());
+ }
+ return page;
+ }
+
+ private ILifecyclePropertyPage loadCurrentPage(IProject project){
+ ILifecyclePropertyPage page = null;
+ try{
+ ILifecycleMapping lifecycleMapping = LifecycleMappingPropertyPageFactory.getLifecycleMapping(project);
+ if(lifecycleMapping == null){
+ return getErrorPage(Messages.MavenProjectLifecycleMappingPage_error_no_strategy);
+ }
+ page = getPage(lifecycleMapping);
+ return page;
+ } catch(CoreException ce){
+ MavenLogger.log(ce);
+ SimpleLifecycleMappingPropertyPage p = new SimpleLifecycleMappingPropertyPage(Messages.MavenProjectLifecycleMappingPage_error_page_error);
+ return p;
+ }
+ }
+
+ protected void performDefaults() {
+ currentPage.performDefaults();
+ }
+
+ protected IProject getProject() {
+ return (IProject) getElement();
+ }
+
+ public boolean performOk() {
+ return currentPage.performOk();
+ }
+
+ public void setElement(IAdaptable element){
+ if(currentPage != null && element instanceof IProject){
+ currentPage.setProject((IProject)element);
+ }
+ super.setElement(element);
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenProjectPreferencePage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenProjectPreferencePage.java
new file mode 100644
index 00000000..b6078c36
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenProjectPreferencePage.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.WorkspaceJob;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.PropertyPage;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.core.project.ResolverConfiguration;
+
+/**
+ * Maven project preference page
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenProjectPreferencePage extends PropertyPage {
+
+ private Button resolveWorspaceProjectsButton;
+// private Button includeModulesButton;
+
+ private Text activeProfilesText;
+
+ public MavenProjectPreferencePage() {
+ setTitle(Messages.MavenProjectPreferencePage_title);
+ }
+
+ protected Control createContents(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+ composite.setLayoutData(new GridData(GridData.FILL));
+
+ Label profilesLabel = new Label(composite, SWT.NONE);
+ profilesLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
+ profilesLabel.setText(Messages.MavenProjectPreferencePage_lblProfiles);
+
+ activeProfilesText = new Text(composite, SWT.BORDER);
+ activeProfilesText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ resolveWorspaceProjectsButton = new Button(composite, SWT.CHECK);
+ GridData resolveWorspaceProjectsButtonData = new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1);
+ resolveWorspaceProjectsButton.setLayoutData(resolveWorspaceProjectsButtonData);
+ resolveWorspaceProjectsButton.setText(Messages.MavenProjectPreferencePage_btnResolve);
+
+// includeModulesButton = new Button(composite, SWT.CHECK);
+// GridData gd = new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1);
+// gd.verticalIndent = 15;
+// includeModulesButton.setLayoutData(gd);
+// includeModulesButton.setText("Include &Modules");
+//
+// Text includeModulesText = new Text(composite, SWT.WRAP | SWT.READ_ONLY | SWT.MULTI);
+// includeModulesText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_BLUE));
+// GridData gd_includeModulesText = new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1);
+// gd_includeModulesText.horizontalIndent = 15;
+// gd_includeModulesText.verticalIndent = 0;
+// gd_includeModulesText.widthHint = 300;
+// gd_includeModulesText.heightHint = 120;
+// includeModulesText.setLayoutData(gd_includeModulesText);
+// includeModulesText.setBackground(composite.getBackground());
+// includeModulesText.setText("When enabled, dependencies from all nested modules "
+// + "are added to the \"Maven Dependencies\" container and "
+// + "source folders from nested modules are added to the current "
+// + "project build path (use \"Update Sources\" action)");
+
+ init(getResolverConfiguration());
+
+ return composite;
+ }
+
+ protected void performDefaults() {
+ init(new ResolverConfiguration());
+ }
+
+ private void init(ResolverConfiguration configuration) {
+
+ resolveWorspaceProjectsButton.setSelection(configuration.shouldResolveWorkspaceProjects());
+// includeModulesButton.setSelection(configuration.shouldIncludeModules());
+ activeProfilesText.setText(configuration.getActiveProfiles());
+ }
+
+ public boolean performOk() {
+ final IProject project = getProject();
+ try {
+ if(!project.isAccessible() || !project.hasNature(IMavenConstants.NATURE_ID)) {
+ return true;
+ }
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ return false;
+ }
+
+ final ResolverConfiguration configuration = getResolverConfiguration();
+ if(configuration.getActiveProfiles().equals(activeProfilesText.getText()) &&
+// configuration.shouldIncludeModules()==includeModulesButton.getSelection() &&
+ configuration.shouldResolveWorkspaceProjects()==resolveWorspaceProjectsButton.getSelection()) {
+ return true;
+ }
+
+ configuration.setResolveWorkspaceProjects(resolveWorspaceProjectsButton.getSelection());
+// configuration.setIncludeModules(includeModulesButton.getSelection());
+ configuration.setActiveProfiles(activeProfilesText.getText());
+
+ MavenProjectManager projectManager = MavenPlugin.getDefault().getMavenProjectManager();
+ boolean isSet = projectManager.setResolverConfiguration(getProject(), configuration);
+ if(isSet) {
+
+ boolean res = MessageDialog.openQuestion(getShell(), Messages.MavenProjectPreferencePage_dialog_title, //
+ Messages.MavenProjectPreferencePage_dialog_message);
+ if(res) {
+ final MavenPlugin plugin = MavenPlugin.getDefault();
+ WorkspaceJob job = new WorkspaceJob(NLS.bind(Messages.MavenProjectPreferencePage_job, project.getName() )) {
+ public IStatus runInWorkspace(IProgressMonitor monitor) {
+ try {
+ plugin.getProjectConfigurationManager().updateProjectConfiguration(project, configuration, monitor);
+ } catch(CoreException ex) {
+ return ex.getStatus();
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.setRule(plugin.getProjectConfigurationManager().getRule());
+ job.schedule();
+ }
+
+ }
+
+ return isSet;
+ }
+
+ private ResolverConfiguration getResolverConfiguration() {
+ MavenProjectManager projectManager = MavenPlugin.getDefault().getMavenProjectManager();
+ return projectManager.getResolverConfiguration(getProject());
+ }
+
+ private IProject getProject() {
+ return (IProject) getElement();
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenSettingsPreferencePage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenSettingsPreferencePage.java
new file mode 100644
index 00000000..788b8726
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MavenSettingsPreferencePage.java
@@ -0,0 +1,413 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.WorkspaceJob;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+
+import org.apache.maven.cli.MavenCli;
+import org.apache.maven.repository.RepositorySystem;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.building.SettingsProblem;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.embedder.IMavenConfiguration;
+import org.eclipse.m2e.core.embedder.MavenRuntime;
+import org.eclipse.m2e.core.embedder.MavenRuntimeManager;
+import org.eclipse.m2e.core.index.IndexManager;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenUpdateRequest;
+
+
+/**
+ * Maven installations preference page
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenSettingsPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
+
+ final MavenPlugin mavenPlugin;
+
+ final MavenRuntimeManager runtimeManager;
+
+ final IMavenConfiguration mavenConfiguration;
+
+ final IMaven maven;
+
+ MavenRuntime defaultRuntime;
+
+
+ Text userSettingsText;
+
+ Text localRepositoryText;
+
+ boolean dirty = false;
+
+ private Link userSettingsLink;
+
+ public MavenSettingsPreferencePage() {
+ setTitle(org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_title);
+
+ this.mavenPlugin = MavenPlugin.getDefault();
+ this.runtimeManager = mavenPlugin.getMavenRuntimeManager();
+ this.mavenConfiguration = MavenPlugin.getDefault().getMavenConfiguration();
+ this.maven = MavenPlugin.getDefault().getMaven();
+ }
+
+ public void init(IWorkbench workbench) {
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.DialogPage#setVisible(boolean)
+ */
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ if(visible){
+ updateLocalRepository();
+ }
+ }
+
+ protected void performDefaults() {
+ userSettingsText.setText(MavenCli.DEFAULT_USER_SETTINGS_FILE.getAbsolutePath());
+ setDirty(true);
+ updateLocalRepository();
+ super.performDefaults();
+ }
+
+ protected void updateSettings(final boolean updateMavenDependencies){
+ final String userSettings = getUserSettings();
+
+ new Job(org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_job_updating) {
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ final File localRepositoryDir = new File(maven.getLocalRepository().getBasedir());
+ if(userSettings.length() > 0) {
+ mavenConfiguration.setUserSettingsFile(userSettings);
+ } else {
+ mavenConfiguration.setUserSettingsFile(null);
+ }
+
+ File newRepositoryDir = new File(maven.getLocalRepository().getBasedir());
+ if(!newRepositoryDir.equals(localRepositoryDir)) {
+ IndexManager indexManager = mavenPlugin.getIndexManager();
+ indexManager.getWorkspaceIndex().updateIndex(true, monitor);
+ }
+ if(updateMavenDependencies){
+ IMavenProjectFacade[] projects = MavenPlugin.getDefault().getMavenProjectManager().getProjects();
+ ArrayList<IProject> allProjects = new ArrayList<IProject>();
+ if(projects != null){
+ MavenPlugin.getDefault().getMaven().reloadSettings();
+ SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, projects.length);
+ for(int i=0;i<projects.length;i++){
+ subMonitor.beginTask(NLS.bind(org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_task_updating, projects[i].getProject().getName()), 1);
+ allProjects.add(projects[i].getProject());
+ }
+ IMavenConfiguration configuration = MavenPlugin.getDefault().getMavenConfiguration();
+ MavenPlugin.getDefault().getMavenProjectManager().refresh(new MavenUpdateRequest(allProjects.toArray(new IProject[]{}), configuration.isOffline(), true));
+ subMonitor.done();
+ }
+ }
+ return Status.OK_STATUS;
+ } catch (CoreException e) {
+ return e.getStatus();
+ }
+ }
+ }.schedule();
+ }
+
+ protected void performApply() {
+ if(dirty){
+ updateSettings(false);
+ }
+ }
+
+ public boolean performOk() {
+ if (dirty) {
+ updateSettings(false);
+ }
+ return true;
+ }
+
+ public void setDirty(boolean dirty){
+ this.dirty = dirty;
+ }
+
+ public boolean isDirty(){
+ return this.dirty;
+ }
+
+ protected Control createContents(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout(4, false);
+ gridLayout.marginBottom = 5;
+ gridLayout.marginRight = 5;
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ composite.setLayout(gridLayout);
+
+ createUserSettings(composite);
+ Label localRepositoryLabel = new Label(composite, SWT.NONE);
+ GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false, 4, 1);
+ gd.verticalIndent=25;
+ localRepositoryLabel.setLayoutData(gd);
+ localRepositoryLabel.setText(org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_lblLocal);
+
+ localRepositoryText = new Text(composite, SWT.READ_ONLY|SWT.BORDER);
+ localRepositoryText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
+ localRepositoryText.setData("name", "localRepositoryText"); //$NON-NLS-1$ //$NON-NLS-2$
+ localRepositoryText.setEditable(false);
+ Button reindexButton = new Button(composite, SWT.NONE);
+ reindexButton.setLayoutData(new GridData(SWT.FILL, SWT.RIGHT, false, false, 1, 1));
+ reindexButton.setText(Messages.getString("preferences.reindexButton")); //$NON-NLS-1$
+ reindexButton.addSelectionListener(new SelectionAdapter(){
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ public void widgetSelected(SelectionEvent e) {
+ new WorkspaceJob(org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_job_indexing) {
+ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
+ IndexManager indexManager = mavenPlugin.getIndexManager();
+ indexManager.getWorkspaceIndex().updateIndex(true, monitor);
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+ });
+ defaultRuntime = runtimeManager.getDefaultRuntime();
+
+ String userSettings = mavenConfiguration.getUserSettingsFile();
+ if(userSettings == null || userSettings.length() == 0) {
+ userSettingsText.setText(MavenCli.DEFAULT_USER_SETTINGS_FILE.getAbsolutePath());
+ } else {
+ userSettingsText.setText(userSettings);
+ }
+
+ checkSettings();
+ updateLocalRepository();
+
+ userSettingsText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent modifyevent) {
+ updateLocalRepository();
+ checkSettings();
+ setDirty(true);
+ }
+ });
+
+ return composite;
+ }
+
+ public void updateSettingsLink(boolean active){
+ String text = org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_link1;
+ if(active){
+ text = org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_link2;
+ }
+ userSettingsLink.setText(text);
+ }
+ /**
+ * @param composite
+ */
+ private void createUserSettings(Composite composite) {
+
+ userSettingsLink = new Link(composite, SWT.NONE);
+ userSettingsLink.setData("name", "userSettingsLink"); //$NON-NLS-1$ //$NON-NLS-2$
+ userSettingsLink.setText(org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_link2);
+ userSettingsLink.setToolTipText(org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_link_tooltip);
+ GridData gd_userSettingsLabel = new GridData(SWT.FILL, SWT.CENTER, true, false, 4, 1);
+
+ gd_userSettingsLabel.verticalIndent = 15;
+ userSettingsLink.setLayoutData(gd_userSettingsLabel);
+ userSettingsLink.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ String userSettings = getUserSettings();
+ if(userSettings.length() == 0) {
+ userSettings = MavenCli.DEFAULT_USER_SETTINGS_FILE.getAbsolutePath();
+ }
+ openEditor(userSettings);
+ }
+ });
+ userSettingsText = new Text(composite, SWT.BORDER);
+ userSettingsText.setData("name", "userSettingsText"); //$NON-NLS-1$ //$NON-NLS-2$
+ GridData gd_userSettingsText = new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1);
+ gd_userSettingsText.verticalIndent = 5;
+ gd_userSettingsText.widthHint = 100;
+ userSettingsText.setLayoutData(gd_userSettingsText);
+
+ Button userSettingsBrowseButton = new Button(composite, SWT.NONE);
+ GridData gd_userSettingsBrowseButton = new GridData(SWT.FILL, SWT.RIGHT, false, false, 1, 1);
+
+ userSettingsBrowseButton.setLayoutData(gd_userSettingsBrowseButton);
+ userSettingsBrowseButton.setText(org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_btnBrowse);
+ userSettingsBrowseButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
+ if(getUserSettings().length() > 0) {
+ dialog.setFileName(getUserSettings());
+ }
+ String file = dialog.open();
+ if(file != null) {
+ file = file.trim();
+ if(file.length() > 0) {
+ userSettingsText.setText(file);
+ updateLocalRepository();
+ checkSettings();
+ }
+ }
+ }
+ });
+
+ Button updateSettings = new Button(composite, SWT.NONE);
+ GridData gd = new GridData(SWT.FILL, SWT.LEFT, false, false, 1, 1);
+ updateSettings.setText(org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_btnUpdate);
+ updateSettings.addSelectionListener(new SelectionAdapter(){
+ public void widgetSelected(SelectionEvent e){
+ updateSettings(true);
+ }
+ });
+ }
+
+ protected void updateLocalRepository() {
+ final String userSettings = getUserSettings();
+ String globalSettings = runtimeManager.getGlobalSettingsFile();
+ try {
+ Settings settings = maven.buildSettings(globalSettings, userSettings);
+ String localRepository = settings.getLocalRepository();
+ if(localRepository == null){
+ localRepository = RepositorySystem.defaultUserLocalRepository.getAbsolutePath();
+ }
+ if(!localRepositoryText.isDisposed()) {
+ localRepositoryText.setText(localRepository == null ? "" : localRepository); //$NON-NLS-1$
+ }
+ } catch (CoreException e) {
+ setMessage(e.getMessage(), IMessageProvider.ERROR);
+ }
+ }
+
+ protected void checkSettings() {
+ setErrorMessage(null);
+ setMessage(null);
+ boolean fileExists = false;
+ String userSettings = getUserSettings();
+ if(userSettings != null && userSettings.length() > 0) {
+ File userSettingsFile = new File(userSettings);
+ if(!userSettingsFile.exists()) {
+ setMessage(org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_error_missing, IMessageProvider.WARNING);
+ userSettings = null;
+
+ } else {
+ fileExists = true;
+ }
+
+ } else {
+ userSettings = null;
+ }
+ updateSettingsLink(fileExists);
+ List<SettingsProblem> result = maven.validateSettings(userSettings);
+ if(result.size() > 0) {
+ setMessage(NLS.bind(org.eclipse.m2e.core.internal.Messages.MavenSettingsPreferencePage_error_parse, result.get(0).getMessage()), IMessageProvider.WARNING);
+ }
+ }
+
+
+
+ @SuppressWarnings("unchecked")
+ void openEditor(final String fileName) {
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+ IWorkbenchPage page = window.getActivePage();
+
+ IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor("settings.xml"); //$NON-NLS-1$
+
+ File file = new File(fileName);
+ IEditorInput input = null;
+ try {
+ //class implementing editor input for external file has been renamed in eclipse 3.3, hence reflection
+ Class javaInput = null;
+ try {
+ javaInput = Class.forName("org.eclipse.ui.internal.editors.text.JavaFileEditorInput"); //$NON-NLS-1$
+ Constructor cons = javaInput.getConstructor(new Class[] {File.class});
+ input = (IEditorInput) cons.newInstance(new Object[] {file});
+ } catch(Exception e) {
+ try {
+ IFileStore fileStore = EFS.getLocalFileSystem().fromLocalFile(file);
+ Class storeInput = Class.forName("org.eclipse.ui.ide.FileStoreEditorInput"); //$NON-NLS-1$
+ Constructor cons = storeInput.getConstructor(new Class[] {IFileStore.class});
+ input = (IEditorInput) cons.newInstance(new Object[] {fileStore});
+ } catch(Exception ex) {
+ //ignore...
+ }
+ }
+ final IEditorPart editor = IDE.openEditor(page, input, desc.getId());
+ editor.addPropertyListener(new IPropertyListener() {
+ public void propertyChanged(Object source, int propId) {
+ if(!editor.isDirty()) {
+ mavenPlugin.getConsole().logMessage("Refreshing settings " + fileName);
+ }
+ }
+ });
+
+ } catch(PartInitException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+
+ String getUserSettings() {
+ return userSettingsText.getText().trim();
+ }
+
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MissingLifecycleMappingPropertyPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MissingLifecycleMappingPropertyPage.java
new file mode 100644
index 00000000..602e7322
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/MissingLifecycleMappingPropertyPage.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.osgi.util.NLS;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.project.MissingLifecycleMapping;
+import org.eclipse.m2e.core.project.configurator.ILifecycleMapping;
+import org.eclipse.m2e.core.ui.internal.lifecycle.LifecycleMappingPropertyPageFactory;
+
+public class MissingLifecycleMappingPropertyPage extends SimpleLifecycleMappingPropertyPage {
+
+ public MissingLifecycleMappingPropertyPage() {
+ super(Messages.MissingLifecycleMappingPropertyPage_title);
+ }
+
+ protected String getMessage() {
+ try {
+ ILifecycleMapping lifecycleMapping = LifecycleMappingPropertyPageFactory.getLifecycleMapping(getProject());
+ if (lifecycleMapping instanceof MissingLifecycleMapping) {
+ String missingId = ((MissingLifecycleMapping) lifecycleMapping).getMissingMappingId();
+ return NLS.bind(Messages.MissingLifecycleMappingPropertyPage_error, missingId);
+ }
+ } catch(CoreException ex) {
+ // this is odd, but lets ignore it anyways
+ }
+ return super.getMessage();
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/ProblemReportingPreferencePage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/ProblemReportingPreferencePage.java
new file mode 100644
index 00000000..90abeaf9
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/ProblemReportingPreferencePage.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.StringFieldEditor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
+
+
+public class ProblemReportingPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+ final MavenPlugin plugin;
+ private Composite parent;
+
+ public ProblemReportingPreferencePage() {
+ super(GRID);
+ setPreferenceStore(MavenPlugin.getDefault().getPreferenceStore());
+
+ plugin = MavenPlugin.getDefault();
+ }
+
+ public void init(IWorkbench workbench) {
+ }
+
+ /*
+ * Creates the field editors. Field editors are abstractions of the common GUI
+ * blocks needed to manipulate various types of preferences. Each field editor
+ * knows how to save and restore itself.
+ */
+ public void createFieldEditors() {
+ parent = getFieldEditorParent();
+
+ addField(new StringFieldEditor(MavenPreferenceConstants.P_JIRA_USERNAME, Messages.getString("jira.username"), parent)); //$NON-NLS-1$
+
+ StringFieldEditor passwordEditor = new StringFieldEditor(MavenPreferenceConstants.P_JIRA_PASSWORD, Messages.getString("jira.password"), parent); //$NON-NLS-1$
+
+ addField(passwordEditor);
+ Text passwordField = passwordEditor.getTextControl(parent);
+ passwordField.setEchoChar('*');
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/RemoteArchetypeCatalogDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/RemoteArchetypeCatalogDialog.java
new file mode 100644
index 00000000..649c89da
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/RemoteArchetypeCatalogDialog.java
@@ -0,0 +1,284 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import org.apache.maven.archetype.catalog.Archetype;
+import org.apache.maven.archetype.catalog.ArchetypeCatalog;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory;
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory.RemoteCatalogFactory;
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * Remote Archetype catalog dialog
+ *
+ * @author Eugene Kuleshov
+ */
+public class RemoteArchetypeCatalogDialog extends TitleAreaDialog {
+
+ /**
+ *
+ */
+ private static final int VERIFY_ID = IDialogConstants.CLIENT_ID + 1;
+
+ private static final String DIALOG_SETTINGS = RemoteArchetypeCatalogDialog.class.getName();
+
+ private static final String KEY_LOCATIONS = "catalogUrl"; //$NON-NLS-1$
+
+ private static final int MAX_HISTORY = 15;
+
+ private String title;
+
+ private String message;
+
+ Combo catalogUrlCombo;
+
+ private Text catalogDescriptionText;
+
+ private IDialogSettings dialogSettings;
+
+ private ArchetypeCatalogFactory archetypeCatalogFactory;
+
+ Button verifyButton;
+
+
+ protected RemoteArchetypeCatalogDialog(Shell shell, ArchetypeCatalogFactory factory) {
+ super(shell);
+ this.archetypeCatalogFactory = factory;
+ this.title = Messages.RemoteArchetypeCatalogDialog_title;
+ this.message = Messages.RemoteArchetypeCatalogDialog_message;
+ setShellStyle(SWT.DIALOG_TRIM);
+
+ IDialogSettings pluginSettings = MavenPlugin.getDefault().getDialogSettings();
+ dialogSettings = pluginSettings.getSection(DIALOG_SETTINGS);
+ if(dialogSettings == null) {
+ dialogSettings = new DialogSettings(DIALOG_SETTINGS);
+ pluginSettings.addSection(dialogSettings);
+ }
+ }
+
+ protected Control createContents(Composite parent) {
+ Control control = super.createContents(parent);
+ setTitle(title);
+ setMessage(message);
+ return control;
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite composite1 = (Composite) super.createDialogArea(parent);
+
+ Composite composite = new Composite(composite1, SWT.NONE);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.marginTop = 7;
+ gridLayout.marginWidth = 12;
+ gridLayout.numColumns = 2;
+ composite.setLayout(gridLayout);
+
+ Label catalogLocationLabel = new Label(composite, SWT.NONE);
+ catalogLocationLabel.setText(Messages.RemoteArchetypeCatalogDialog_lblCatalog);
+
+ catalogUrlCombo = new Combo(composite, SWT.NONE);
+ GridData gd_catalogLocationCombo = new GridData(SWT.FILL, SWT.CENTER, true, false);
+ gd_catalogLocationCombo.widthHint = 250;
+ catalogUrlCombo.setLayoutData(gd_catalogLocationCombo);
+ catalogUrlCombo.setItems(getSavedValues(KEY_LOCATIONS));
+
+ Label catalogDescriptionLabel = new Label(composite, SWT.NONE);
+ catalogDescriptionLabel.setText(Messages.RemoteArchetypeCatalogDialog_lblDesc);
+
+ catalogDescriptionText = new Text(composite, SWT.BORDER);
+ catalogDescriptionText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ if(archetypeCatalogFactory!=null) {
+ catalogUrlCombo.setText(archetypeCatalogFactory.getId());
+ catalogDescriptionText.setText(archetypeCatalogFactory.getDescription());
+ }
+
+ ModifyListener modifyListener = new ModifyListener() {
+ public void modifyText(final ModifyEvent e) {
+ update();
+ }
+ };
+ catalogUrlCombo.addModifyListener(modifyListener);
+ catalogDescriptionText.addModifyListener(modifyListener);
+
+ return composite;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.TrayDialog#createButtonBar(org.eclipse.swt.widgets.Composite)
+ */
+ protected Control createButtonBar(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
+ layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
+ layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+ layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+ composite.setLayout(layout);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ composite.setFont(parent.getFont());
+
+ // create help control if needed
+ if(isHelpAvailable()) {
+ createHelpControl(composite);
+ }
+
+ verifyButton = createButton(composite, VERIFY_ID, Messages.RemoteArchetypeCatalogDialog_btnVerify, false);
+ verifyButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ verifyButton.setEnabled(false);
+ String url = catalogUrlCombo.getText();
+ final RemoteCatalogFactory factory = new RemoteCatalogFactory(url, null, true);
+
+ new Job(Messages.RemoteArchetypeCatalogDialog_job_download) {
+ protected IStatus run(IProgressMonitor monitor) {
+ IStatus status = Status.OK_STATUS;
+ ArchetypeCatalog catalog = null;
+ try {
+ catalog = factory.getArchetypeCatalog();
+ } finally {
+ final IStatus s = status;
+ @SuppressWarnings("unchecked")
+ final List<Archetype> archetypes = catalog==null ? Collections.emptyList() : catalog.getArchetypes();
+ getShell().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ verifyButton.setEnabled(true);
+ if(!s.isOK()) {
+ setErrorMessage(NLS.bind(Messages.RemoteArchetypeCatalogDialog_error_read,s.getMessage()));
+ getButton(IDialogConstants.OK_ID).setEnabled(false);
+ } else if(archetypes.size()==0) {
+ setMessage(Messages.RemoteArchetypeCatalogDialog_error_empty, IStatus.WARNING);
+ } else {
+ setMessage(NLS.bind(Messages.RemoteArchetypeCatalogDialog_message_found, archetypes.size()), IStatus.INFO);
+ }
+ }
+ });
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+ });
+
+ Label filler= new Label(composite, SWT.NONE);
+ filler.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
+ layout.numColumns++;
+
+ super.createButtonsForButtonBar(composite); // cancel button
+
+ return composite;
+ }
+
+ protected Button getButton(int id) {
+ return super.getButton(id);
+ }
+
+ private String[] getSavedValues(String key) {
+ String[] array = dialogSettings.getArray(key);
+ return array == null ? new String[0] : array;
+ }
+
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ shell.setText(title);
+ }
+
+ public void create() {
+ super.create();
+ getButton(IDialogConstants.OK_ID).setEnabled(false);
+ getButton(VERIFY_ID).setEnabled(false);
+ }
+
+ protected void okPressed() {
+ String description = catalogDescriptionText.getText().trim();
+ String location = catalogUrlCombo.getText().trim();
+
+ archetypeCatalogFactory = new RemoteCatalogFactory(location, description, true);
+
+ saveValue(KEY_LOCATIONS, location);
+
+ super.okPressed();
+ }
+
+ public ArchetypeCatalogFactory getArchetypeCatalogFactory() {
+ return archetypeCatalogFactory;
+ }
+
+ private void saveValue(String key, String value) {
+ List<String> dirs = new ArrayList<String>();
+ dirs.addAll(Arrays.asList(getSavedValues(key)));
+
+ dirs.remove(value);
+ dirs.add(0, value);
+
+ if(dirs.size() > MAX_HISTORY) {
+ dirs = dirs.subList(0, MAX_HISTORY);
+ }
+
+ dialogSettings.put(key, dirs.toArray(new String[dirs.size()]));
+ }
+
+ void update() {
+ boolean isValid = isValid();
+ getButton(IDialogConstants.OK_ID).setEnabled(isValid);
+ getButton(VERIFY_ID).setEnabled(isValid);
+ }
+
+ private boolean isValid() {
+ setErrorMessage(null);
+ setMessage(null, IStatus.WARNING);
+
+
+ String url = catalogUrlCombo.getText().trim();
+ if(url.length()==0) {
+ setErrorMessage(Messages.RemoteArchetypeCatalogDialog_error_required);
+ verifyButton.setEnabled(false);
+ return false;
+ }
+
+ verifyButton.setEnabled(true);
+ return true;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/SimpleLifecycleMappingPropertyPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/SimpleLifecycleMappingPropertyPage.java
new file mode 100644
index 00000000..76f8df82
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/preferences/SimpleLifecycleMappingPropertyPage.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.preferences;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+
+import org.eclipse.m2e.core.ui.internal.lifecycle.AbstractLifecyclePropertyPage;
+
+
+/**
+ * Simple lifecycle mapping properties page that displays static text.
+ *
+ * @author igor
+ */
+public class SimpleLifecycleMappingPropertyPage extends AbstractLifecyclePropertyPage {
+
+ private String message;
+
+ public SimpleLifecycleMappingPropertyPage(String message) {
+ this.message = message;
+ }
+
+ public Control createContents(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+ composite.setLayoutData(new GridData(GridData.FILL));
+ Label noInfoLabel = new Label(composite, SWT.NONE);
+ noInfoLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 2, 1));
+ noInfoLabel.setAlignment(SWT.CENTER);
+ noInfoLabel.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY));
+ noInfoLabel.setData("name", "noInfoLabel"); //$NON-NLS-1$ //$NON-NLS-2$
+ noInfoLabel.setText(getMessage());
+ return composite;
+ }
+
+ protected String getMessage() {
+ return message;
+ }
+
+ public void performDefaults() {
+ }
+
+ public boolean performOk() {
+ return true;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchPage.java
new file mode 100644
index 00000000..38cdb6f1
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchPage.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.search;
+
+import org.eclipse.jface.dialogs.DialogPage;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.search.ui.ISearchPage;
+import org.eclipse.search.ui.ISearchPageContainer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * Maven Search Page
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenSearchPage extends DialogPage implements ISearchPage {
+
+ private Table table;
+ private Combo classNameText;
+ private Combo sha1Text;
+ private Combo versionText;
+ private Combo packagingIdText;
+ private Combo artifactIdText;
+ private Combo groupIdText;
+
+ // private ISearchPageContainer container;
+
+ public MavenSearchPage() {
+ }
+
+ public MavenSearchPage(String title) {
+ super(title);
+ }
+
+ public MavenSearchPage(String title, ImageDescriptor image) {
+ super(title, image);
+ }
+
+ public void setContainer(ISearchPageContainer container) {
+ // this.container = container;
+ }
+
+ public boolean performAction() {
+ // TODO Auto-generated method performAction
+ return false;
+ }
+
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(3, false));
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ setControl(parent);
+
+ Label groupIdLabel = new Label(composite, SWT.NONE);
+ groupIdLabel.setText(Messages.MavenSearchPage_lblGroupid);
+
+ groupIdText = new Combo(composite, SWT.NONE);
+ groupIdText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ Label artifactIdLabel = new Label(composite, SWT.NONE);
+ artifactIdLabel.setText(Messages.MavenSearchPage_lblArtifactid);
+
+ artifactIdText = new Combo(composite, SWT.NONE);
+ artifactIdText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ Label versionLabel = new Label(composite, SWT.NONE);
+ versionLabel.setText(Messages.MavenSearchPage_lblVersion);
+
+ versionText = new Combo(composite, SWT.NONE);
+ versionText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ Label packagingIdLabel = new Label(composite, SWT.NONE);
+ packagingIdLabel.setText(Messages.MavenSearchPage_lblPackaging);
+
+ packagingIdText = new Combo(composite, SWT.NONE);
+ GridData packagingIdTextData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1);
+ packagingIdTextData.widthHint = 208;
+ packagingIdText.setLayoutData(packagingIdTextData);
+
+ Label sha1Label = new Label(composite, SWT.NONE);
+ sha1Label.setText(Messages.MavenSearchPage_lblSha);
+
+ sha1Text = new Combo(composite, SWT.NONE);
+ sha1Text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ Button browseButton = new Button(composite, SWT.NONE);
+ browseButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ browseButton.setText(Messages.MavenSearchPage_btnBrowse);
+
+ Label classNameLabel = new Label(composite, SWT.NONE);
+ classNameLabel.setText(Messages.MavenSearchPage_lblClass);
+
+ classNameText = new Combo(composite, SWT.NONE);
+ classNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ Label separator = new Label(composite, SWT.HORIZONTAL | SWT.SEPARATOR);
+ GridData separatorData = new GridData(SWT.FILL, SWT.TOP, false, false, 3, 1);
+ separatorData.heightHint = 15;
+ separatorData.minimumHeight = 15;
+ separator.setLayoutData(separatorData);
+ separator.setText(Messages.MavenSearchPage_separator);
+
+ Label repositoriesLabel = new Label(composite, SWT.NONE);
+ repositoriesLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
+ repositoriesLabel.setText(Messages.MavenSearchPage_lblRepos);
+
+ CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(composite, SWT.BORDER);
+ table = tableViewer.getTable();
+ table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2));
+
+ Button selectAllButton = new Button(composite, SWT.NONE);
+ selectAllButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ selectAllButton.setText(Messages.MavenSearchPage_btnSelect);
+ new Label(composite, SWT.NONE);
+
+ Button deselectAllButton = new Button(composite, SWT.NONE);
+ deselectAllButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ deselectAllButton.setText(Messages.MavenSearchPage_btnUnselect);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchResult.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchResult.java
new file mode 100644
index 00000000..a464aeea
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchResult.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.search;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.search.ui.ISearchQuery;
+import org.eclipse.search.ui.text.AbstractTextSearchResult;
+import org.eclipse.search.ui.text.IEditorMatchAdapter;
+import org.eclipse.search.ui.text.IFileMatchAdapter;
+
+/**
+ * Maven search result
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenSearchResult extends AbstractTextSearchResult {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.ISearchResult#getQuery()
+ */
+ public ISearchQuery getQuery() {
+ // TODO Auto-generated method getQuery
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.ISearchResult#getLabel()
+ */
+ public String getLabel() {
+ // TODO Auto-generated method getLabel
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.ISearchResult#getImageDescriptor()
+ */
+ public ImageDescriptor getImageDescriptor() {
+ // TODO Auto-generated method getImageDescriptor
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.ISearchResult#getTooltip()
+ */
+ public String getTooltip() {
+ // TODO Auto-generated method getTooltip
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.text.AbstractTextSearchResult#getEditorMatchAdapter()
+ */
+ public IEditorMatchAdapter getEditorMatchAdapter() {
+ // TODO Auto-generated method getEditorMatchAdapter
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.text.AbstractTextSearchResult#getFileMatchAdapter()
+ */
+ public IFileMatchAdapter getFileMatchAdapter() {
+ // TODO Auto-generated method getFileMatchAdapter
+ return null;
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchResultPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchResultPage.java
new file mode 100644
index 00000000..d0c28aae
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/search/MavenSearchResultPage.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.search;
+
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.search.ui.text.AbstractTextSearchViewPage;
+import org.eclipse.ui.IMemento;
+
+/**
+ * Maven search result page
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenSearchResultPage extends AbstractTextSearchViewPage {
+
+ public MavenSearchResultPage() {
+ super(FLAG_LAYOUT_TREE | FLAG_LAYOUT_FLAT);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#configureTableViewer(org.eclipse.jface.viewers.TableViewer)
+ */
+ protected void configureTableViewer(TableViewer viewer) {
+ // TODO Auto-generated method configureTableViewer
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#configureTreeViewer(org.eclipse.jface.viewers.TreeViewer)
+ */
+ protected void configureTreeViewer(TreeViewer viewer) {
+ // TODO Auto-generated method configureTreeViewer
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#clear()
+ */
+ protected void clear() {
+ // TODO Auto-generated method clear
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#elementsChanged(java.lang.Object[])
+ */
+ protected void elementsChanged(Object[] objects) {
+ // TODO Auto-generated method elementsChanged
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#restoreState(org.eclipse.ui.IMemento)
+ */
+ public void restoreState(IMemento memento) {
+ super.restoreState(memento);
+
+ // TODO Auto-generated method restoreState
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#saveState(org.eclipse.ui.IMemento)
+ */
+ public void saveState(IMemento memento) {
+ super.saveState(memento);
+ // TODO Auto-generated method saveState
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/MavenRepositoryView.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/MavenRepositoryView.java
new file mode 100644
index 00000000..08547ca7
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/MavenRepositoryView.java
@@ -0,0 +1,596 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.WorkspaceJob;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.actions.BaseSelectionListenerAction;
+import org.eclipse.ui.part.DrillDownAdapter;
+import org.eclipse.ui.part.ViewPart;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.actions.MaterializeAction;
+import org.eclipse.m2e.core.actions.OpenPomAction;
+import org.eclipse.m2e.core.index.IndexListener;
+import org.eclipse.m2e.core.index.IndexManager;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.index.IndexedArtifactGroup;
+import org.eclipse.m2e.core.internal.index.NexusIndex;
+import org.eclipse.m2e.core.repository.IRepository;
+import org.eclipse.m2e.core.ui.internal.views.nodes.AbstractIndexedRepositoryNode;
+import org.eclipse.m2e.core.ui.internal.views.nodes.IArtifactNode;
+import org.eclipse.m2e.core.ui.internal.views.nodes.IndexedArtifactFileNode;
+import org.eclipse.m2e.core.ui.internal.views.nodes.LocalRepositoryNode;
+import org.eclipse.m2e.core.ui.internal.views.nodes.RepositoryNode;
+import org.eclipse.m2e.core.util.M2EUtils;
+
+
+/**
+ * Maven repository view
+ *
+ * @author dyocum
+ */
+public class MavenRepositoryView extends ViewPart {
+ private static final String ENABLE_FULL = Messages.MavenRepositoryView_enable_full;
+ private static final String ENABLED_FULL = Messages.MavenRepositoryView_enabled_full;
+ private static final String DISABLE_DETAILS = Messages.MavenRepositoryView_disable_details;
+ private static final String DISABLED_DETAILS = Messages.MavenRepositoryView_details_disabled;
+ private static final String ENABLE_MIN = Messages.MavenRepositoryView_enable_minimum;
+ private static final String ENABLED_MIN = Messages.MavenRepositoryView_minimum_enabled;
+
+ private IndexManager indexManager = MavenPlugin.getDefault().getIndexManager();
+
+ private IAction collapseAllAction;
+
+ private IAction reloadSettings;
+
+ BaseSelectionListenerAction openPomAction;
+
+ private BaseSelectionListenerAction updateAction;
+
+ private BaseSelectionListenerAction rebuildAction;
+
+ private DisableIndexAction disableAction;
+ private EnableMinIndexAction enableMinAction;
+ private EnableFullIndexAction enableFullAction;
+
+ private BaseSelectionListenerAction copyUrlAction;
+
+ private BaseSelectionListenerAction materializeProjectAction;
+
+ TreeViewer viewer;
+ private RepositoryViewContentProvider contentProvider;
+
+ private DrillDownAdapter drillDownAdapter;
+
+ private IndexListener indexListener;
+
+ public void setFocus() {
+ viewer.getControl().setFocus();
+ }
+
+ public void createPartControl(Composite parent) {
+ viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ contentProvider = new RepositoryViewContentProvider();
+ viewer.setContentProvider(contentProvider);
+ viewer.setLabelProvider(new RepositoryViewLabelProvider(viewer.getTree().getFont()));
+
+ viewer.addDoubleClickListener(new IDoubleClickListener() {
+ public void doubleClick(DoubleClickEvent event) {
+
+ }
+ });
+ viewer.setInput(getViewSite());
+ drillDownAdapter = new DrillDownAdapter(viewer);
+
+ makeActions();
+ hookContextMenu();
+
+ viewer.addDoubleClickListener(new IDoubleClickListener() {
+ public void doubleClick(DoubleClickEvent event) {
+ openPomAction.run();
+ }
+ });
+
+ contributeToActionBars();
+ this.indexListener = new IndexListener() {
+
+ public void indexAdded(IRepository repository) {
+ refreshView();
+ }
+
+ public void indexChanged(IRepository repository) {
+ refreshView();
+ }
+
+ public void indexRemoved(IRepository repository) {
+ refreshView();
+ }
+
+ public void indexUpdating(IRepository repository){
+ Display.getDefault().asyncExec(new Runnable(){
+ public void run(){
+ viewer.refresh(true);
+ }
+ });
+ }
+ };
+
+ indexManager.addIndexListener(this.indexListener);
+ }
+
+ private void hookContextMenu() {
+ MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
+ menuMgr.setRemoveAllWhenShown(true);
+ menuMgr.addMenuListener(new IMenuListener() {
+ public void menuAboutToShow(IMenuManager manager) {
+ MavenRepositoryView.this.fillContextMenu(manager);
+ }
+ });
+
+ Menu menu = menuMgr.createContextMenu(viewer.getControl());
+ viewer.getControl().setMenu(menu);
+ getSite().registerContextMenu(menuMgr, viewer);
+ }
+
+ private void contributeToActionBars() {
+ IActionBars bars = getViewSite().getActionBars();
+ fillLocalPullDown(bars.getMenuManager());
+ fillLocalToolBar(bars.getToolBarManager());
+ }
+
+ private void fillLocalPullDown(IMenuManager manager) {
+ manager.add(new Separator());
+ manager.add(collapseAllAction);
+ manager.add(reloadSettings);
+ }
+
+ protected List<AbstractIndexedRepositoryNode> getSelectedRepositoryNodes(List elements){
+ ArrayList<AbstractIndexedRepositoryNode> list = new ArrayList<AbstractIndexedRepositoryNode>();
+ if (elements != null) {
+ for(int i=0;i<elements.size();i++){
+ Object elem = elements.get(i);
+ if(elem instanceof AbstractIndexedRepositoryNode) {
+ list.add((AbstractIndexedRepositoryNode)elem);
+ }
+ }
+ }
+ return list;
+ }
+ protected List<IArtifactNode> getArtifactNodes(List elements){
+ if(elements == null || elements.size() == 0){
+ return null;
+ }
+ ArrayList<IArtifactNode> list = new ArrayList<IArtifactNode>();
+ for(int i=0;i<elements.size();i++){
+ Object elem = elements.get(i);
+ if(elem instanceof IArtifactNode){
+ IArtifactNode node = (IArtifactNode)elem;
+ list.add(node);
+ }
+ }
+ return list;
+ }
+ void fillContextMenu(IMenuManager manager) {
+ manager.add(openPomAction);
+ manager.add(copyUrlAction);
+ manager.add(materializeProjectAction);
+ manager.add(new Separator());
+ manager.add(updateAction);
+ manager.add(rebuildAction);
+ manager.add(new Separator());
+ manager.add(disableAction);
+ manager.add(enableMinAction);
+ manager.add(enableFullAction);
+// manager.add(deleteFromLocalAction);
+ manager.add(new Separator());
+ manager.add(collapseAllAction);
+ manager.add(new Separator());
+ drillDownAdapter.addNavigationActions(manager);
+ manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+ }
+
+ private void fillLocalToolBar(IToolBarManager manager) {
+ manager.add(new Separator());
+ manager.add(collapseAllAction);
+ manager.add(reloadSettings);
+ manager.add(new Separator());
+ drillDownAdapter.addNavigationActions(manager);
+ }
+
+ private void makeActions() {
+ collapseAllAction = new Action(Messages.MavenRepositoryView_btnCollapse) {
+ public void run() {
+ viewer.collapseAll();
+ }
+ };
+ collapseAllAction.setToolTipText(Messages.MavenRepositoryView_btnCollapse_tooltip);
+ collapseAllAction.setImageDescriptor(MavenImages.COLLAPSE_ALL);
+ reloadSettings = new Action(Messages.MavenRepositoryView_action_reload){
+ public void run(){
+ String msg = Messages.MavenRepositoryView_reload_msg;
+ boolean res = MessageDialog.openConfirm(getViewSite().getShell(), //
+ Messages.MavenRepositoryView_reload_title, msg);
+ if(res){
+ Job job = new WorkspaceJob(Messages.MavenRepositoryView_job_reloading) {
+ public IStatus runInWorkspace(IProgressMonitor monitor) {
+ try {
+ MavenPlugin.getDefault().getMaven().reloadSettings();
+ } catch(CoreException ex) {
+ return ex.getStatus();
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.schedule();
+ }
+ }
+ };
+
+ reloadSettings.setImageDescriptor(MavenImages.REFRESH);
+// deleteFromLocalAction = new BaseSelectionListenerAction("Delete from Repository") {
+// public void run() {
+// List<IArtifactNode> nodes = getArtifactNodes(getStructuredSelection().toList());
+// if(nodes != null){
+// for(IArtifactNode node : nodes){
+// String key = node.getDocumentKey();
+// System.out.println("key: "+key);
+// ((NexusIndexManager)MavenPlugin.getDefault().getIndexManager()).removeDocument("local", null, key);
+// }
+// }
+// }
+//
+// protected boolean updateSelection(IStructuredSelection selection) {
+// List<IArtifactNode> nodes = getArtifactNodes(getStructuredSelection().toList());
+// return (nodes != null && nodes.size() > 0);
+// }
+// };
+// deleteFromLocalAction.setToolTipText("Delete the selected GAV from the local repository");
+ //updateAction.setImageDescriptor(MavenImages.UPD_INDEX);
+
+
+ updateAction = new BaseSelectionListenerAction(Messages.MavenRepositoryView_action_update) {
+ public void run() {
+ List<AbstractIndexedRepositoryNode> nodes = getSelectedRepositoryNodes(getStructuredSelection().toList());
+ for(AbstractIndexedRepositoryNode node : nodes) {
+ if (node instanceof RepositoryNode) {
+ ((RepositoryNode) node).getIndex().scheduleIndexUpdate(false);
+ }
+ }
+ }
+
+ protected boolean updateSelection(IStructuredSelection selection) {
+ int indexCount = 0;
+ for (AbstractIndexedRepositoryNode node : getSelectedRepositoryNodes(selection.toList())) {
+ if (node instanceof RepositoryNode && node.isEnabledIndex()) {
+ indexCount ++;
+ }
+ }
+ if(indexCount > 1){
+ setText(Messages.MavenRepositoryView_update_more);
+ } else {
+ setText(Messages.MavenRepositoryView_update_one);
+ }
+ return indexCount > 0;
+ }
+ };
+ updateAction.setToolTipText(Messages.MavenRepositoryView_btnUpdate_tooltip);
+ updateAction.setImageDescriptor(MavenImages.UPD_INDEX);
+
+ rebuildAction = new BaseSelectionListenerAction(Messages.MavenRepositoryView_action_rebuild) {
+ public void run() {
+ List<AbstractIndexedRepositoryNode> nodes = getSelectedRepositoryNodes(getStructuredSelection().toList());
+ if(nodes.size() > 0){
+ if(nodes.size() == 1){
+ NexusIndex index = nodes.get(0).getIndex();
+ if (index != null) {
+ String repositoryUrl = index.getRepositoryUrl();
+ String msg = NLS.bind(Messages.MavenRepositoryView_rebuild_msg, repositoryUrl);
+ boolean res = MessageDialog.openConfirm(getViewSite().getShell(), //
+ Messages.MavenRepositoryView_rebuild_title, msg);
+ if(res) {
+ index.scheduleIndexUpdate(true);
+ }
+ }
+ } else {
+ String msg = Messages.MavenRepositoryView_rebuild_msg2;
+ boolean res = MessageDialog.openConfirm(getViewSite().getShell(), //
+ Messages.MavenRepositoryView_rebuild_title2, msg);
+ if(res) {
+ for(AbstractIndexedRepositoryNode node : nodes){
+ NexusIndex index = node.getIndex();
+ if (index != null) {
+ index.scheduleIndexUpdate(true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ protected boolean updateSelection(IStructuredSelection selection) {
+ int indexCount = 0;
+ for (AbstractIndexedRepositoryNode node : getSelectedRepositoryNodes(selection.toList())) {
+ if ((node instanceof LocalRepositoryNode) || node.isEnabledIndex()) {
+ indexCount ++;
+ }
+ }
+ if(indexCount > 1){
+ setText(Messages.MavenRepositoryView_rebuild_many);
+ } else {
+ setText(Messages.MavenRepositoryView_rebuild_one);
+ }
+ return indexCount > 0;
+ }
+ };
+
+ rebuildAction.setToolTipText(Messages.MavenRepositoryView_action_rebuild_tooltip);
+ rebuildAction.setImageDescriptor(MavenImages.REBUILD_INDEX);
+
+ disableAction = new DisableIndexAction();
+
+ disableAction.setToolTipText(Messages.MavenRepositoryView_action_disable_tooltip);
+ disableAction.setImageDescriptor(MavenImages.REBUILD_INDEX);
+
+ enableMinAction = new EnableMinIndexAction();
+ enableMinAction.setToolTipText(Messages.MavenRepositoryView_action_enable_tooltip);
+ enableMinAction.setImageDescriptor(MavenImages.REBUILD_INDEX);
+
+ enableFullAction = new EnableFullIndexAction();
+ enableFullAction.setToolTipText(Messages.MavenRepositoryView_action_enableFull_tooltip);
+ enableFullAction.setImageDescriptor(MavenImages.REBUILD_INDEX);
+
+ openPomAction = new BaseSelectionListenerAction(Messages.MavenRepositoryView_action_open) {
+ public void run() {
+ ISelection selection = viewer.getSelection();
+ Object element = ((IStructuredSelection) selection).getFirstElement();
+ if(element instanceof IndexedArtifactFileNode) {
+ IndexedArtifactFile f = ((IndexedArtifactFileNode) element).getIndexedArtifactFile();
+ OpenPomAction.openEditor(f.group, f.artifact, f.version, null);
+ }
+ }
+
+ protected boolean updateSelection(IStructuredSelection selection) {
+ return selection.getFirstElement() instanceof IndexedArtifactFile;
+ }
+ };
+ openPomAction.setToolTipText(Messages.MavenRepositoryView_action_open_tooltip);
+ openPomAction.setImageDescriptor(MavenImages.POM);
+
+ copyUrlAction = new BaseSelectionListenerAction(Messages.MavenRepositoryView_action_copy) {
+ public void run() {
+ Object element = getStructuredSelection().getFirstElement();
+ String url = null;
+ if(element instanceof RepositoryNode) {
+ url = ((RepositoryNode) element).getRepositoryUrl();
+ } else if(element instanceof IndexedArtifactGroup) {
+ IndexedArtifactGroup group = (IndexedArtifactGroup) element;
+ String repositoryUrl = group.getRepository().getUrl();
+ if(!repositoryUrl.endsWith("/")) { //$NON-NLS-1$
+ repositoryUrl += "/"; //$NON-NLS-1$
+ }
+ url = repositoryUrl + group.getPrefix().replace('.', '/');
+ } else if(element instanceof IndexedArtifact) {
+ //
+ } else if(element instanceof IndexedArtifactFile) {
+ //
+ }
+ if(url != null) {
+ Clipboard clipboard = new Clipboard(Display.getCurrent());
+ clipboard.setContents(new String[] {url}, new Transfer[] {TextTransfer.getInstance()});
+ clipboard.dispose();
+ }
+ }
+
+ protected boolean updateSelection(IStructuredSelection selection) {
+ Object element = selection.getFirstElement();
+ return element instanceof RepositoryNode;
+ }
+ };
+ copyUrlAction.setToolTipText(Messages.MavenRepositoryView_action_copy_tooltip);
+ copyUrlAction.setImageDescriptor(MavenImages.COPY);
+
+ materializeProjectAction = new BaseSelectionListenerAction(Messages.MavenRepositoryView_action_materialize) {
+ public void run() {
+ Object element = getStructuredSelection().getFirstElement();
+ if(element instanceof IndexedArtifactFileNode){
+ MaterializeAction action = new MaterializeAction();
+ StructuredSelection sel = new StructuredSelection(new Object[]{((IndexedArtifactFileNode) element).getIndexedArtifactFile()});
+ action.selectionChanged(this, sel);
+ action.run(this);
+ }
+ }
+
+ protected boolean updateSelection(IStructuredSelection selection) {
+ return selection.getFirstElement() instanceof IndexedArtifactFileNode;
+ }
+ };
+ materializeProjectAction.setImageDescriptor(MavenImages.IMPORT_PROJECT);
+
+ viewer.addSelectionChangedListener(openPomAction);
+ viewer.addSelectionChangedListener(updateAction);
+ viewer.addSelectionChangedListener(disableAction);
+ viewer.addSelectionChangedListener(enableMinAction);
+ viewer.addSelectionChangedListener(enableFullAction);
+ viewer.addSelectionChangedListener(rebuildAction);
+ viewer.addSelectionChangedListener(copyUrlAction);
+ viewer.addSelectionChangedListener(materializeProjectAction);
+ }
+
+ protected void setIndexDetails(AbstractIndexedRepositoryNode node, String details) {
+ if (node != null && node.getIndex() != null) {
+ try {
+ node.getIndex().setIndexDetails(details);
+ } catch(CoreException ex) {
+ M2EUtils.showErrorDialog(this.getViewSite().getShell(), Messages.MavenRepositoryView_error_title, Messages.MavenRepositoryView_error_message, ex);
+ }
+ }
+ }
+
+ protected AbstractIndexedRepositoryNode getSelectedRepositoryNode(IStructuredSelection selection) {
+ List elements = selection.toList();
+ if (elements.size() != 1) {
+ return null;
+ }
+ Object element = elements.get(0);
+ return element instanceof AbstractIndexedRepositoryNode? (AbstractIndexedRepositoryNode) element: null;
+ }
+
+ public void dispose() {
+ viewer.removeSelectionChangedListener(materializeProjectAction);
+ viewer.removeSelectionChangedListener(copyUrlAction);
+ viewer.removeSelectionChangedListener(rebuildAction);
+ viewer.removeSelectionChangedListener(disableAction);
+ viewer.removeSelectionChangedListener(enableMinAction);
+ viewer.removeSelectionChangedListener(enableFullAction);
+ viewer.removeSelectionChangedListener(updateAction);
+ viewer.removeSelectionChangedListener(openPomAction);
+ indexManager.removeIndexListener(this.indexListener);
+ super.dispose();
+ }
+
+ void refreshView() {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ Object[] expandedElems = viewer.getExpandedElements();
+ if (!viewer.getControl().isDisposed()) {
+ viewer.setInput(getViewSite());
+ if(expandedElems != null && expandedElems.length > 0){
+ viewer.setExpandedElements(expandedElems);
+ }
+ }
+ }
+ });
+ };
+
+ /**
+ * Base Selection Listener does not allow the style (radio button/check) to be set.
+ * This base class listens to selections and sets the appropriate index value
+ * depending on its value
+ * AbstractIndexAction
+ *
+ * @author dyocum
+ */
+ abstract class AbstractIndexAction extends Action implements ISelectionChangedListener{
+
+ protected abstract String getDetailsValue();
+ protected abstract String getActionText();
+
+ public AbstractIndexAction(String text, int style){
+ super(text, style);
+ }
+
+ public void run() {
+ IStructuredSelection sel = (IStructuredSelection)viewer.getSelection();
+ setIndexDetails(getSelectedRepositoryNode(sel), getDetailsValue());
+ }
+
+ /*
+ */
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection sel = (IStructuredSelection)event.getSelection();
+ updateSelection(sel);
+ }
+
+ protected void updateSelection(IStructuredSelection selection) {
+ AbstractIndexedRepositoryNode node = getSelectedRepositoryNode(selection);
+ updateIndexDetails(node);
+ setText(getActionText());
+ boolean enabled = (node != null && node instanceof RepositoryNode);
+ this.setEnabled(enabled);
+ }
+
+ protected void updateIndexDetails(AbstractIndexedRepositoryNode node){
+ if(node == null || node.getIndex() == null){
+ return;
+ }
+ NexusIndex index = node.getIndex();
+ setChecked(getDetailsValue().equals(index.getIndexDetails()));
+ }
+
+ }
+
+ class DisableIndexAction extends AbstractIndexAction {
+ public DisableIndexAction(){
+ super(DISABLE_DETAILS, IAction.AS_CHECK_BOX);
+ }
+
+ protected String getDetailsValue(){
+ return NexusIndex.DETAILS_DISABLED;
+ }
+ protected String getActionText(){
+ return isChecked() ? DISABLED_DETAILS : DISABLE_DETAILS;
+ }
+ }
+
+ class EnableMinIndexAction extends AbstractIndexAction {
+ public EnableMinIndexAction(){
+ super(ENABLE_MIN, IAction.AS_CHECK_BOX);
+ }
+
+ protected String getDetailsValue(){
+ return NexusIndex.DETAILS_MIN;
+ }
+ protected String getActionText(){
+ return isChecked() ? ENABLED_MIN : ENABLE_MIN;
+ }
+ }
+
+ class EnableFullIndexAction extends AbstractIndexAction {
+ public EnableFullIndexAction(){
+ super(ENABLE_FULL, IAction.AS_CHECK_BOX);
+ }
+
+ protected String getDetailsValue(){
+ return NexusIndex.DETAILS_FULL;
+ }
+ protected String getActionText(){
+ return isChecked() ? ENABLED_FULL : ENABLE_FULL;
+ }
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/RepositoryViewContentProvider.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/RepositoryViewContentProvider.java
new file mode 100644
index 00000000..9a0b3fe0
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/RepositoryViewContentProvider.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.IViewSite;
+
+import org.eclipse.m2e.core.ui.internal.views.nodes.CustomRepositoriesNode;
+import org.eclipse.m2e.core.ui.internal.views.nodes.GlobalRepositoriesNode;
+import org.eclipse.m2e.core.ui.internal.views.nodes.IMavenRepositoryNode;
+import org.eclipse.m2e.core.ui.internal.views.nodes.LocalRepositoryRootNode;
+import org.eclipse.m2e.core.ui.internal.views.nodes.ProjectRepositoriesNode;
+
+/**
+ * RepositoryViewContentProvider
+ *
+ * @author dyocum
+ */
+public class RepositoryViewContentProvider implements IStructuredContentProvider, ITreeContentProvider {
+
+ private LocalRepositoryRootNode localNode;
+ private GlobalRepositoriesNode globalNode;
+ private ProjectRepositoriesNode projectNode;
+ private CustomRepositoriesNode customNode;
+
+ public RepositoryViewContentProvider() {
+ }
+
+ public void inputChanged(Viewer v, Object oldInput, Object newInput) {
+ }
+
+ public void dispose() {
+ }
+
+ public Object[] getElements(Object parent) {
+ return getChildren(parent);
+ }
+
+ public Object getParent(Object child) {
+ return null;
+ }
+
+ public boolean hasChildren(Object parent) {
+ if(parent instanceof IMavenRepositoryNode){
+ return ((IMavenRepositoryNode)parent).hasChildren();
+ }
+ return false;
+ }
+
+ public Object[] getRootNodes(){
+ if(localNode == null){
+ localNode = new LocalRepositoryRootNode();
+
+ }
+ if(globalNode == null){
+ globalNode = new GlobalRepositoriesNode();
+ }
+ if(projectNode == null) {
+ projectNode = new ProjectRepositoriesNode();
+ }
+ if(customNode == null) {
+ customNode = new CustomRepositoriesNode();
+ }
+ return new Object[]{localNode, globalNode, projectNode, customNode};
+ }
+
+ public Object[] getChildren(Object parent) {
+ if(parent instanceof IViewSite){
+ return getRootNodes();
+ } else if(parent instanceof IMavenRepositoryNode){
+ return ((IMavenRepositoryNode)parent).getChildren();
+ }
+ return new Object[0];
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/RepositoryViewLabelProvider.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/RepositoryViewLabelProvider.java
new file mode 100644
index 00000000..0ac86c34
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/RepositoryViewLabelProvider.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views;
+
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.IFontProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.m2e.core.ui.internal.views.nodes.IMavenRepositoryNode;
+import org.eclipse.m2e.core.ui.internal.views.nodes.RepositoryNode;
+import org.eclipse.m2e.core.util.M2EUtils;
+
+/**
+ * RepositoryViewLabelProvider
+ *
+ * @author dyocum
+ */
+public class RepositoryViewLabelProvider extends LabelProvider implements IColorProvider, IFontProvider {
+
+ private Font italicFont;
+ public RepositoryViewLabelProvider(Font treeFont){
+ int size = 0;
+ FontData[] data = treeFont.getFontData();
+ if(data == null){
+ size = 12;
+ } else {
+ for(int i=0;i<data.length;i++){
+ size = Math.max(size, data[i].getHeight());
+ }
+ }
+ italicFont = M2EUtils.deriveFont(treeFont, SWT.ITALIC, size);
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.BaseLabelProvider#dispose()
+ */
+ public void dispose() {
+ italicFont.dispose();
+ super.dispose();
+ }
+
+
+ public String getText(Object obj) {
+ if(obj instanceof IMavenRepositoryNode){
+ return ((IMavenRepositoryNode)obj).getName();
+ }
+ return obj.toString();
+ }
+
+ public Image getImage(Object obj) {
+ if(obj instanceof IMavenRepositoryNode){
+ return ((IMavenRepositoryNode)obj).getImage();
+ }
+ return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT);
+ }
+
+ public Color getBackground(Object element) {
+ return null;
+ }
+
+ public Color getForeground(Object element) {
+ if(element instanceof RepositoryNode){
+ if(((RepositoryNode)element).isEnabledIndex()){
+ return Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ }
+ return Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY);
+ }
+ return Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ }
+
+ public Font getFont(Object element) {
+ if(element instanceof IMavenRepositoryNode){
+ boolean updating = ((IMavenRepositoryNode)element).isUpdating();
+ return updating ? italicFont : null;
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/AbstractIndexedRepositoryNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/AbstractIndexedRepositoryNode.java
new file mode 100644
index 00000000..a6fb9f55
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/AbstractIndexedRepositoryNode.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import java.util.Arrays;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.index.IndexedArtifactGroup;
+import org.eclipse.m2e.core.internal.index.NexusIndex;
+
+
+/**
+ * AbstractIndexedRepository
+ *
+ * @author igor
+ */
+public abstract class AbstractIndexedRepositoryNode implements IMavenRepositoryNode {
+
+ protected static final Object[] NO_CHILDREN = new Object[0];
+
+ protected final NexusIndex index;
+
+ protected AbstractIndexedRepositoryNode(NexusIndex index) {
+ this.index = index;
+ }
+
+ public Object[] getChildren() {
+
+ if(index == null) {
+ return NO_CHILDREN;
+ }
+
+ try {
+ IndexedArtifactGroup[] rootGroups = index.getRootIndexedArtifactGroups();
+ if(rootGroups == null) {
+ return NO_CHILDREN;
+ }
+ IndexedArtifactGroupNode[] children = new IndexedArtifactGroupNode[rootGroups.length];
+ Arrays.sort(rootGroups);
+ for(int i = 0; i < rootGroups.length; i++ ) {
+ children[i] = new IndexedArtifactGroupNode(rootGroups[i]);
+ }
+ return children;
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ return NO_CHILDREN;
+ }
+ }
+
+ public Image getImage() {
+ return MavenImages.IMG_INDEX;
+ }
+
+ public boolean hasChildren() {
+ return index != null;
+ }
+
+ public boolean isUpdating() {
+ return index != null && index.isUpdating();
+ }
+
+ public NexusIndex getIndex() {
+ return index;
+ }
+
+ public String getRepositoryUrl() {
+ return index.getRepositoryUrl();
+ }
+
+ public boolean isEnabledIndex() {
+ return index != null && index.isEnabled();
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/AbstractRepositoriesNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/AbstractRepositoriesNode.java
new file mode 100644
index 00000000..bb80d447
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/AbstractRepositoriesNode.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.internal.index.NexusIndex;
+import org.eclipse.m2e.core.internal.index.NexusIndexManager;
+import org.eclipse.m2e.core.repository.IRepository;
+import org.eclipse.m2e.core.repository.IRepositoryRegistry;
+
+/**
+ * AbstractRepositoriesNode
+ *
+ * @author igor
+ */
+public abstract class AbstractRepositoriesNode implements IMavenRepositoryNode {
+
+ protected final NexusIndexManager indexManager = (NexusIndexManager) MavenPlugin.getDefault().getIndexManager();
+ protected final IRepositoryRegistry repositoryRegistry = MavenPlugin.getDefault().getRepositoryRegistry();
+
+ public Object[] getChildren() {
+
+ ArrayList<Object> mirrorNodes = new ArrayList<Object>();
+ ArrayList<Object> globalRepoNodes = new ArrayList<Object>();
+
+ for (IRepository repo : getRepositories()) {
+ NexusIndex index = indexManager.getIndex(repo);
+ RepositoryNode node = new RepositoryNode(index);
+ if (repo.getMirrorOf() != null) {
+ mirrorNodes.add(node);
+ } else {
+ globalRepoNodes.add(node);
+ }
+ }
+
+ ArrayList<Object> nodes = new ArrayList<Object>();
+ nodes.addAll(mirrorNodes);
+ nodes.addAll(globalRepoNodes);
+
+ return nodes.toArray(new Object[nodes.size()]);
+ }
+
+ protected abstract List<IRepository> getRepositories();
+
+ public String toString() {
+ return getName();
+ }
+
+ public boolean hasChildren() {
+ Object[] kids = getChildren();
+ return kids != null && kids.length > 0;
+ }
+
+ public Image getImage() {
+ return MavenImages.IMG_INDEXES;
+ }
+
+ public boolean isUpdating() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/CustomRepositoriesNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/CustomRepositoriesNode.java
new file mode 100644
index 00000000..678dcbdd
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/CustomRepositoriesNode.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import java.util.List;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.repository.IRepository;
+import org.eclipse.m2e.core.repository.IRepositoryRegistry;
+
+/**
+ * CustomRepositoriesNode
+ *
+ * @author igor
+ */
+public class CustomRepositoriesNode extends AbstractRepositoriesNode {
+
+ protected List<IRepository> getRepositories() {
+ return repositoryRegistry.getRepositories(IRepositoryRegistry.SCOPE_UNKNOWN);
+ }
+
+ public String getName() {
+ return Messages.CustomRepositoriesNode_name;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/GlobalRepositoriesNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/GlobalRepositoriesNode.java
new file mode 100644
index 00000000..7eef0deb
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/GlobalRepositoriesNode.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import java.util.List;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.repository.IRepository;
+import org.eclipse.m2e.core.repository.IRepositoryRegistry;
+
+
+/**
+ * Parent node for all artifact repositories and mirrors defined in settings.xml.
+ *
+ * @author dyocum
+ */
+public class GlobalRepositoriesNode extends AbstractRepositoriesNode {
+
+ public String getName() {
+ return Messages.GlobalRepositoriesNode_name;
+ }
+
+ protected List<IRepository> getRepositories() {
+ return repositoryRegistry.getRepositories(IRepositoryRegistry.SCOPE_SETTINGS);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IArtifactNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IArtifactNode.java
new file mode 100644
index 00000000..54c908fb
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IArtifactNode.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+
+/**
+ * AbstractArtifactNode
+ *
+ * @author dyocum
+ */
+public interface IArtifactNode {
+ public String getDocumentKey();
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IMavenRepositoryNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IMavenRepositoryNode.java
new file mode 100644
index 00000000..b296ca7f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IMavenRepositoryNode.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * MavenRepositoryRootNode
+ *
+ * @author dyocum
+ */
+public interface IMavenRepositoryNode {
+
+ public Object[] getChildren();
+ public String getName();
+ public Image getImage();
+ public boolean hasChildren();
+ public boolean isUpdating();
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactFileNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactFileNode.java
new file mode 100644
index 00000000..4f9d5702
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactFileNode.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.internal.index.NexusIndexManager;
+
+/**
+ * IndexedArtifactFileNode
+ *
+ * @author dyocum
+ */
+public class IndexedArtifactFileNode implements IMavenRepositoryNode, IArtifactNode {
+
+ private IndexedArtifactFile artifactFile;
+
+ public IndexedArtifactFileNode(IndexedArtifactFile artifactFile){
+ this.artifactFile = artifactFile;
+ }
+
+ public IndexedArtifactFile getIndexedArtifactFile(){
+ return this.artifactFile;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.IMavenRepositoryNode#getChildren()
+ */
+ public Object[] getChildren() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.IMavenRepositoryNode#getName()
+ */
+ public String getName() {
+ String label = artifactFile.artifact;
+ if(artifactFile.classifier != null) {
+ label += " : " + artifactFile.classifier; //$NON-NLS-1$
+ }
+ if(artifactFile.version != null) {
+ label += " : " + artifactFile.version; //$NON-NLS-1$
+ }
+ return label;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.IMavenRepositoryNode#hasChildren()
+ */
+ public boolean hasChildren() {
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.nodes.IMavenRepositoryNode#getImage()
+ */
+ public Image getImage() {
+ if(artifactFile.sourcesExists == IIndex.PRESENT) {
+ return MavenImages.IMG_VERSION_SRC;
+ }
+ return MavenImages.IMG_VERSION;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.nodes.IArtifactNode#getDocumentKey()
+ */
+ public String getDocumentKey() {
+ return NexusIndexManager.getDocumentKey(artifactFile.getArtifactKey());
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.nodes.IMavenRepositoryNode#isUpdating()
+ */
+ public boolean isUpdating() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactGroupNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactGroupNode.java
new file mode 100644
index 00000000..28f5b5c4
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactGroupNode.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.internal.index.IndexedArtifactGroup;
+import org.eclipse.m2e.core.internal.index.NexusIndexManager;
+
+/**
+ * IndexedArtifactGroupNode
+ *
+ * @author dyocum
+ */
+public class IndexedArtifactGroupNode implements IMavenRepositoryNode, IArtifactNode {
+
+ private IndexedArtifactGroup indexedArtifactGroup;
+ private Object[] kids = null;
+ public IndexedArtifactGroupNode(IndexedArtifactGroup group){
+ this.indexedArtifactGroup = group;
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.IMavenRepositoryNode#getChildren()
+ */
+ public Object[] getChildren() {
+ NexusIndexManager indexManager = (NexusIndexManager) MavenPlugin.getDefault().getIndexManager();
+
+ IndexedArtifactGroup resolvedGroup = indexManager.resolveGroup(indexedArtifactGroup);
+ //IndexedArtifactGroup resolvedGroup = indexedArtifactGroup;
+ ArrayList<Object> results = new ArrayList<Object>();
+ Collection<IndexedArtifactGroup> groups = resolvedGroup.getNodes().values();
+ for(IndexedArtifactGroup group : groups){
+ IndexedArtifactGroupNode node = new IndexedArtifactGroupNode(group);
+ results.add(node);
+ }
+
+ Collection<IndexedArtifact> artifacts = resolvedGroup.getFiles().values(); // IndexedArtifact
+ for(IndexedArtifact artifact : artifacts){
+ IndexedArtifactNode artifactNode = new IndexedArtifactNode(artifact);
+ results.add(artifactNode);
+ }
+ kids = results.toArray(new Object[results.size()]);
+ return kids;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.IMavenRepositoryNode#getName()
+ */
+ public String getName() {
+ String prefix = indexedArtifactGroup.getPrefix();
+ int n = prefix.lastIndexOf('.');
+ return n < 0 ? prefix : prefix.substring(n + 1);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.IMavenRepositoryNode#hasChildren()
+ */
+ public boolean hasChildren() {
+// if(kids == null){
+// kids = getChildren();
+// }
+// return kids != null && kids.length > 0;
+ return true;
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.nodes.IMavenRepositoryNode#getImage()
+ */
+ public Image getImage() {
+ return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER);
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.nodes.IArtifactNode#getDocumentKey()
+ */
+ public String getDocumentKey() {
+ return indexedArtifactGroup.getPrefix();
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.nodes.IMavenRepositoryNode#isUpdating()
+ */
+ public boolean isUpdating() {
+ // TODO Auto-generated method isUpdating
+ return false;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactNode.java
new file mode 100644
index 00000000..23c3a8e0
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/IndexedArtifactNode.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * IndexedArtifactNode
+ *
+ * @author dyocum
+ */
+public class IndexedArtifactNode implements IMavenRepositoryNode, IArtifactNode {
+
+ private IndexedArtifact artifact;
+ private Object[] kids = null;
+ public IndexedArtifactNode(IndexedArtifact artifact){
+ this.artifact = artifact;
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.IMavenRepositoryNode#getChildren()
+ */
+ public Object[] getChildren() {
+ Set<IndexedArtifactFile> files = artifact.getFiles();
+ if(files == null){
+ return new Object[0];
+ }
+ ArrayList<Object> fileList = new ArrayList<Object>();
+ for(IndexedArtifactFile iaf : files){
+ fileList.add(new IndexedArtifactFileNode(iaf));
+ }
+ kids = fileList.toArray(new IndexedArtifactFileNode[fileList.size()]);
+ return kids;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.IMavenRepositoryNode#getName()
+ */
+ public String getName() {
+ // return a.group + ":" + a.artifact;
+ String pkg = artifact.getPackaging();
+ if(pkg == null){
+ pkg = Messages.IndexedArtifactNode_no_pack;
+ }
+ return artifact.getArtifactId() + " - " + pkg; //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.IMavenRepositoryNode#hasChildren()
+ */
+ public boolean hasChildren() {
+ //return kids != null && kids.length > 0;
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.nodes.IMavenRepositoryNode#getImage()
+ */
+ public Image getImage() {
+ return MavenImages.IMG_JAR;
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.nodes.IArtifactNode#getDocumentKey()
+ */
+ public String getDocumentKey() {
+ return artifact.getArtifactId();
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.ui.internal.views.nodes.IMavenRepositoryNode#isUpdating()
+ */
+ public boolean isUpdating() {
+ // TODO Auto-generated method isUpdating
+ return false;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/LocalRepositoryNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/LocalRepositoryNode.java
new file mode 100644
index 00000000..e46218be
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/LocalRepositoryNode.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.index.NexusIndex;
+import org.eclipse.m2e.core.repository.IRepository;
+
+/**
+ * LocalRepositoryNode
+ *
+ * @author igor
+ */
+public class LocalRepositoryNode extends AbstractIndexedRepositoryNode {
+
+ public LocalRepositoryNode(NexusIndex index) {
+ super(index);
+ }
+
+ public String getName() {
+ IRepository repository = index.getRepository();
+ StringBuilder sb = new StringBuilder();
+ sb.append(Messages.LocalRepositoryNode_local);
+ if (repository.getBasedir() != null) {
+ sb.append(" (").append(repository.getBasedir().getAbsolutePath()).append(')'); //$NON-NLS-1$
+ }
+ return sb.toString();
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/LocalRepositoryRootNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/LocalRepositoryRootNode.java
new file mode 100644
index 00000000..69b6bb17
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/LocalRepositoryRootNode.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.index.NexusIndex;
+import org.eclipse.m2e.core.internal.index.NexusIndexManager;
+
+/**
+ * LocalRepositoryNode
+ *
+ * @author dyocum
+ */
+public class LocalRepositoryRootNode implements IMavenRepositoryNode{
+
+ public Object[] getChildren() {
+ NexusIndexManager indexManager = (NexusIndexManager) MavenPlugin.getDefault().getIndexManager();
+ NexusIndex localIndex = indexManager.getLocalIndex();
+ NexusIndex workspaceIndex = indexManager.getWorkspaceIndex();
+ return new Object[]{
+ new LocalRepositoryNode(localIndex),
+ new WorkspaceRepositoryNode(workspaceIndex)
+ };
+ }
+
+ public String getName() {
+ return Messages.LocalRepositoryRootNode_name;
+ }
+
+ public boolean hasChildren() {
+ return true;
+ }
+
+ public Image getImage() {
+ return MavenImages.IMG_INDEXES;
+ }
+
+ public boolean isUpdating() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/ProjectRepositoriesNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/ProjectRepositoriesNode.java
new file mode 100644
index 00000000..2c96cc27
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/ProjectRepositoriesNode.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import java.util.ArrayList;
+
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.index.NexusIndex;
+import org.eclipse.m2e.core.internal.index.NexusIndexManager;
+import org.eclipse.m2e.core.repository.IRepository;
+import org.eclipse.m2e.core.repository.IRepositoryRegistry;
+
+
+/**
+ * Parent node for all artifact repositories configured in pom.xml files.
+ */
+public class ProjectRepositoriesNode implements IMavenRepositoryNode {
+
+ private NexusIndexManager indexManager = (NexusIndexManager) MavenPlugin.getDefault().getIndexManager();
+ private IRepositoryRegistry repositoryRegistry = MavenPlugin.getDefault().getRepositoryRegistry();
+
+ public Object[] getChildren() {
+ ArrayList<Object> nodes = new ArrayList<Object>();
+ for(IRepository repo : repositoryRegistry.getRepositories(IRepositoryRegistry.SCOPE_PROJECT)) {
+ NexusIndex index = indexManager.getIndex(repo);
+ RepositoryNode node = new RepositoryNode(index);
+ nodes.add(node);
+ }
+ return nodes.toArray(new Object[nodes.size()]);
+ }
+
+ public Image getImage() {
+ return MavenImages.IMG_INDEXES;
+ }
+
+ public String getName() {
+ return Messages.ProjectRepositoriesNode_name;
+ }
+
+ public String toString() {
+ return getName();
+ }
+
+ public boolean hasChildren() {
+ Object[] kids = getChildren();
+ return kids != null && kids.length > 0;
+ }
+
+ public boolean isUpdating() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/RepositoryNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/RepositoryNode.java
new file mode 100644
index 00000000..849df8bf
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/RepositoryNode.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.index.NexusIndex;
+import org.eclipse.m2e.core.repository.IRepository;
+
+/**
+ * LocalRepsoitoryNode
+ *
+ * @author dyocum
+ */
+public class RepositoryNode extends AbstractIndexedRepositoryNode {
+
+ private final IRepository repository;
+
+ public RepositoryNode(NexusIndex index){
+ super(index);
+ this.repository = index.getRepository();
+ }
+
+ public String getName() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(repository.getId());
+ sb.append(" (").append(repository.getUrl()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (repository.getMirrorOf() != null) {
+ sb.append(" [mirrorOf=").append(repository.getMirrorOf()).append("]"); //$NON-NLS-2$
+ }
+ if (repository.getMirrorId() != null) {
+ sb.append(" [mirrored by ").append(repository.getMirrorId()).append("]"); //$NON-NLS-2$
+ }
+ if (isUpdating()) {
+ sb.append(Messages.RepositoryNode_updating);
+ }
+ return sb.toString();
+ }
+
+ public String getRepositoryUrl() {
+ return repository.getUrl();
+ }
+
+ public String getRepoName() {
+ return repository.toString();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/WorkspaceRepositoryNode.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/WorkspaceRepositoryNode.java
new file mode 100644
index 00000000..4cbb19fe
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/ui/internal/views/nodes/WorkspaceRepositoryNode.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.ui.internal.views.nodes;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.index.NexusIndex;
+
+/**
+ * WorkspaceRepositoryNode
+ *
+ * @author igor
+ */
+public class WorkspaceRepositoryNode extends AbstractIndexedRepositoryNode {
+
+ public WorkspaceRepositoryNode(NexusIndex index) {
+ super(index);
+ }
+
+ public String getName() {
+ return Messages.WorkspaceRepositoryNode_name;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/M2EErrorDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/M2EErrorDialog.java
new file mode 100644
index 00000000..37a4a96f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/M2EErrorDialog.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util;
+
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TableColumn;
+
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * M2EErrorDialog
+ * Error dialog for displaying a list/table of error values.
+ *
+ * @author dyocum
+ */
+public class M2EErrorDialog extends MessageDialog {
+
+
+ private TableViewer errorTable;
+ private static final int PROJECT_COL = 0;
+ protected static final int TABLE_WIDTH = 700;
+ protected String[] COL_NAMES = {Messages.M2EErrorDialog_column_name, Messages.M2EErrorDialog_column_error};
+ protected int[] COL_STYLES = {SWT.LEFT, SWT.LEFT};
+ protected Map<String, Throwable> errorMap;
+
+ /**
+ * @param parentShell
+ * @param dialogTitle
+ * @param dialogTitleImage
+ * @param dialogMessage
+ * @param dialogImageType
+ * @param dialogButtonLabels
+ * @param defaultIndex
+ */
+ public M2EErrorDialog(Shell parentShell, String dialogTitle, Image dialogTitleImage, String dialogMessage,
+ int dialogImageType, String[] dialogButtonLabels, int defaultIndex, Map<String, Throwable> errorMap) {
+ super(parentShell, dialogTitle, dialogTitleImage, dialogMessage, dialogImageType, dialogButtonLabels, defaultIndex);
+ this.errorMap = errorMap;
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ }
+
+ protected Control createCustomArea(Composite parent) {
+ Composite comp = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout(1, true);
+ comp.setLayout(layout);
+
+ GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.widthHint = TABLE_WIDTH+50;
+ gd.grabExcessHorizontalSpace=true;
+ gd.grabExcessVerticalSpace=true;
+ comp.setLayoutData(gd);
+
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.widthHint = TABLE_WIDTH;
+ gd.heightHint = 200;
+ errorTable = new TableViewer(comp, SWT.BORDER|SWT.H_SCROLL|SWT.V_SCROLL|SWT.FULL_SELECTION);
+ errorTable.getTable().setHeaderVisible(true);
+ errorTable.getTable().setLinesVisible(true);
+
+ errorTable.setContentProvider(new ErrorTableContentProvider());
+ errorTable.setLabelProvider(new ErrorTableLabelProvider());
+ errorTable.getControl().setLayoutData(gd);
+
+ setupTableColumns();
+ errorTable.setInput(errorMap);
+ return comp;
+ }
+
+ /**
+ * Create the table columns and set up their widths
+ */
+ protected void setupTableColumns() {
+ GC gc = new GC(errorTable.getControl());
+ gc.setFont(errorTable.getControl().getFont());
+ for(int i=0;i<COL_NAMES.length;i++){
+ TableColumn col = new TableColumn(errorTable.getTable(), COL_STYLES[i]);
+ col.setText(COL_NAMES[i]);
+ int width = calcStringWidth(gc, i);
+ col.setWidth(width);
+ }
+ gc.dispose();
+ }
+
+ /**
+ * Find out how wide the strings are so the columns can be set correctly.
+ * @param gc
+ * @param column
+ * @return
+ */
+ private int calcStringWidth(GC gc, int column){
+ int maxWidth = 100;
+ if(column == PROJECT_COL){
+ Set<String> keySet = errorMap.keySet();
+ for(String projectName : keySet){
+ int width = gc.stringExtent(projectName).x+10;
+ maxWidth = Math.max(maxWidth, width);
+ }
+ return maxWidth;
+ }
+ Collection<Throwable> values = errorMap.values();
+ for(Throwable t : values){
+ String msg = M2EUtils.getRootCauseMessage(t);
+ if(msg == null){
+ msg = ""; //$NON-NLS-1$
+ }
+ int width = gc.stringExtent(msg).x+10;
+ maxWidth = Math.max(maxWidth, width);
+ }
+ return maxWidth;
+ }
+
+ /**
+ * ErrorTableContentProvider
+ *
+ * @author dyocum
+ */
+ class ErrorTableContentProvider implements IStructuredContentProvider {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
+ */
+ public Object[] getElements(Object inputElement) {
+ if(inputElement instanceof Map){
+ return ((Map)inputElement).keySet().toArray();
+ }
+ return new Object[0];
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+ */
+ public void dispose() {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
+ */
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+ }
+
+ class ErrorTableLabelProvider implements ITableLabelProvider{
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
+ */
+ public Image getColumnImage(Object element, int columnIndex) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
+ */
+ public String getColumnText(Object element, int columnIndex) {
+ if(columnIndex == PROJECT_COL){
+ return element.toString();
+ }
+ String msg = M2EUtils.getRootCauseMessage(errorMap.get(element));
+ return msg == null ? "" : msg; //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
+ */
+ public void addListener(ILabelProviderListener listener) {
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
+ */
+ public void dispose() {
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
+ */
+ public boolean isLabelProperty(Object element, String property) {
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
+ */
+ public void removeListener(ILabelProviderListener listener) {
+ }
+ }
+
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/M2EUtils.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/M2EUtils.java
new file mode 100644
index 00000000..8bb6e156
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/M2EUtils.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util;
+
+import java.util.Map;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * M2EUtils
+ *
+ * @author dyocum
+ */
+public class M2EUtils {
+
+ public static Font deriveFont(Font f, int style, int height){
+ FontData[] fd = f.getFontData();
+ FontData[] newFD = new FontData[fd.length];
+ for(int i=0;i<fd.length;i++){
+ newFD[i] = new FontData(fd[i].getName(), height, style);
+ }
+ return new Font(Display.getCurrent(), newFD);
+ }
+
+ public static void showErrorDialog(Shell shell, String title, String msg, Exception e){
+ StringBuffer buff = new StringBuffer(msg);
+ Throwable t = getRootCause(e);
+ if(t != null && !nullOrEmpty(t.getMessage())){
+ buff.append(t.getMessage());
+ }
+ MessageDialog.openError(shell, title, buff.toString());
+ }
+
+ public static String getRootCauseMessage(Throwable t){
+ Throwable root = getRootCause(t);
+ if(t == null){
+ return null;
+ }
+ return root.getMessage();
+ }
+
+ public static Throwable getRootCause(Throwable ex) {
+ if(ex == null){
+ return null;
+ }
+ Throwable rootCause = ex;
+ Throwable cause = rootCause.getCause();
+ while(cause != null && cause != rootCause) {
+ rootCause = cause;
+ cause = cause.getCause();
+ }
+ return cause == null ? rootCause : cause;
+ }
+
+ public static boolean nullOrEmpty(String s){
+ return s == null || s.length() == 0;
+ }
+
+ /**
+ * @param shell
+ * @param string
+ * @param string2
+ * @param updateErrors
+ */
+ public static void showErrorsForProjectsDialog(final Shell shell, final String title, final String message,
+ final Map<String, Throwable> errorMap) {
+ // TODO Auto-generated method showErrorsForProjectsDialog
+ Display.getDefault().asyncExec(new Runnable(){
+ public void run(){
+ String[] buttons = {IDialogConstants.OK_LABEL};
+ int ok_button = 0;
+ M2EErrorDialog errDialog = new M2EErrorDialog(shell, title, Dialog.getImage(Dialog.DLG_IMG_MESSAGE_ERROR), message, MessageDialog.ERROR, buttons, ok_button,
+ errorMap);
+ errDialog.create();
+ errDialog.open();
+ }
+ });
+
+ }
+
+ public static void addRequiredDecoration(Control control) {
+ FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration(
+ FieldDecorationRegistry.DEC_REQUIRED);
+ ControlDecoration controlDecoration = new ControlDecoration(control, SWT.LEFT | SWT.CENTER);
+ controlDecoration.setDescriptionText(fieldDecoration.getDescription());
+ controlDecoration.setImage(fieldDecoration.getImage());
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/ProposalUtil.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/ProposalUtil.java
new file mode 100644
index 00000000..68320167
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/ProposalUtil.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Sonatype, Inc.
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.fieldassist.ContentProposalAdapter;
+import org.eclipse.jface.fieldassist.FieldDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.fieldassist.IContentProposal;
+import org.eclipse.jface.fieldassist.IContentProposalProvider;
+import org.eclipse.jface.fieldassist.IControlContentAdapter;
+import org.eclipse.jface.fieldassist.TextContentAdapter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.util.search.CComboContentAdapter;
+import org.eclipse.m2e.core.util.search.ControlDecoration;
+import org.eclipse.m2e.core.util.search.Packaging;
+import org.eclipse.m2e.core.util.search.SearchEngine;
+
+
+/**
+ * Holds the proposal utility code, previously in the editor.xml plug-in. Provides proposal suggestions for text and
+ * combo widgets for various metadata (group, artifact, etc.)
+ *
+ * @author rgould
+ */
+public class ProposalUtil {
+
+ public static abstract class Searcher {
+ public abstract Collection<String> search() throws CoreException;
+ }
+
+ public static final class TextProposal implements IContentProposal {
+ private final String text;
+
+ public TextProposal(String text) {
+ this.text = text;
+ }
+
+ public int getCursorPosition() {
+ return text.length();
+ }
+
+ public String getContent() {
+ return text;
+ }
+
+ public String getLabel() {
+ return text;
+ }
+
+ public String getDescription() {
+ return null;
+ }
+ }
+
+ public static void addCompletionProposal(final Control control, final Searcher searcher) {
+ FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration(
+ FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
+ ControlDecoration decoration = new ControlDecoration(control, SWT.LEFT | SWT.TOP);
+ decoration.setShowOnlyOnFocus(true);
+ decoration.setDescriptionText(fieldDecoration.getDescription());
+ decoration.setImage(fieldDecoration.getImage());
+
+ IContentProposalProvider proposalProvider = new IContentProposalProvider() {
+ public IContentProposal[] getProposals(String contents, int position) {
+ ArrayList<IContentProposal> proposals = new ArrayList<IContentProposal>();
+ try {
+ for(final String text : searcher.search()) {
+ proposals.add(new TextProposal(text));
+ }
+ } catch(CoreException e) {
+ MavenLogger.log(e);
+ }
+ return proposals.toArray(new IContentProposal[proposals.size()]);
+ }
+ };
+
+ IControlContentAdapter contentAdapter;
+ if(control instanceof Text) {
+ contentAdapter = new TextContentAdapter();
+ } else {
+ contentAdapter = new CComboContentAdapter();
+ }
+
+ ContentAssistCommandAdapter adapter = new ContentAssistCommandAdapter( //
+ control, contentAdapter, proposalProvider, //
+ ContentAssistCommandAdapter.CONTENT_PROPOSAL_COMMAND, null);
+ // ContentProposalAdapter adapter = new ContentProposalAdapter(control, contentAdapter, //
+ // proposalProvider, KeyStroke.getInstance(SWT.MOD1, ' '), null);
+ adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
+ adapter.setPopupSize(new Point(250, 120));
+ adapter.setPopupSize(new Point(250, 120));
+ }
+
+ public static void addClassifierProposal(final IProject project, final Text groupIdText, final Text artifactIdText,
+ final Text versionText, final Text classifierText, final Packaging packaging) {
+ addCompletionProposal(classifierText, new Searcher() {
+ public Collection<String> search() throws CoreException {
+ return getSearchEngine(project).findClassifiers(groupIdText.getText(), //
+ artifactIdText.getText(), versionText.getText(), classifierText.getText(), packaging);
+ }
+ });
+ }
+
+ public static void addVersionProposal(final IProject project, final Text groupIdText, final Text artifactIdText,
+ final Text versionText, final Packaging packaging) {
+ addCompletionProposal(versionText, new Searcher() {
+ public Collection<String> search() throws CoreException {
+ return getSearchEngine(project).findVersions(groupIdText.getText(), //
+ artifactIdText.getText(), versionText.getText(), packaging);
+ }
+ });
+ }
+
+ public static void addArtifactIdProposal(final IProject project, final Text groupIdText, final Text artifactIdText,
+ final Packaging packaging) {
+ addCompletionProposal(artifactIdText, new Searcher() {
+ public Collection<String> search() throws CoreException {
+ // TODO handle artifact info
+ return getSearchEngine(project).findArtifactIds(groupIdText.getText(), artifactIdText.getText(), packaging,
+ null);
+ }
+ });
+ }
+
+ public static void addGroupIdProposal(final IProject project, final Text groupIdText, final Packaging packaging) {
+ addCompletionProposal(groupIdText, new Searcher() {
+ public Collection<String> search() throws CoreException {
+ // TODO handle artifact info
+ return getSearchEngine(project).findGroupIds(groupIdText.getText(), packaging, null);
+ }
+ });
+ }
+
+ public static SearchEngine getSearchEngine(final IProject project) throws CoreException {
+ return MavenPlugin.getDefault().getSearchEngine(project);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/Util.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/Util.java
new file mode 100644
index 00000000..fa01cbae
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/Util.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.variables.VariablesPlugin;
+
+import org.eclipse.m2e.core.core.MavenLogger;
+
+
+/**
+ * Utility methods
+ *
+ * @author Eugene Kuleshov
+ */
+public class Util {
+
+ public static boolean isEclipseVersion(int major, int minor) {
+ Bundle bundle = ResourcesPlugin.getPlugin().getBundle();
+ String version = (String) bundle.getHeaders().get(org.osgi.framework.Constants.BUNDLE_VERSION);
+ Version v = Version.parseVersion(version);
+ return v.getMajor() == major && v.getMinor() == minor;
+ }
+
+ /**
+ * Proxy factory for compatibility stubs
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T proxy(final Object o, Class<T> type) {
+ return (T) Proxy.newProxyInstance(type.getClassLoader(), //
+ new Class[] {type}, //
+ new InvocationHandler() {
+ public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
+ try {
+ Method mm = o.getClass().getMethod(m.getName(), m.getParameterTypes());
+ return mm.invoke(o, args);
+ } catch(final NoSuchMethodException e) {
+ return null;
+ }
+ }
+ });
+ }
+
+ /**
+ * Stub interface for FileStoreEditorInput
+ *
+ * @see Util#proxy(Object, Class)
+ */
+ public static interface FileStoreEditorInputStub {
+ public java.net.URI getURI();
+ }
+
+ /**
+ * Helper method which creates a folder and, recursively, all its parent folders.
+ *
+ * @param folder The folder to create.
+ * @param derived true if folder should be marked as derived
+ * @throws CoreException if creating the given <code>folder</code> or any of its parents fails.
+ */
+ public static void createFolder(IFolder folder, boolean derived) throws CoreException {
+ // Recurse until we find a parent folder which already exists.
+ if(!folder.exists()) {
+ IContainer parent = folder.getParent();
+ // First, make sure that all parent folders exist.
+ if(parent != null && !parent.exists()) {
+ createFolder((IFolder) parent, false);
+ }
+ folder.create(true, true, null);
+ }
+
+ if(folder.isAccessible() && derived) {
+ folder.setDerived(true);
+ }
+ }
+
+ public static void setDerived(IFolder folder, boolean derived) throws CoreException {
+ if(folder.isAccessible()) {
+ folder.setDerived(derived);
+ }
+ }
+
+ /**
+ * Substitute any variable
+ */
+ public static String substituteVar(String s) {
+ if(s == null) {
+ return s;
+ }
+ try {
+ return VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(s);
+ } catch(CoreException e) {
+ MavenLogger.log(e);
+ return null;
+ }
+ }
+
+ public static String nvl(String s) {
+ return s == null ? "" : s; //$NON-NLS-1$
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/ArtifactInfo.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/ArtifactInfo.java
new file mode 100644
index 00000000..85b90527
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/ArtifactInfo.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util.search;
+
+
+/**
+ * Information about the artifact.
+ *
+ * @author Lukas Krecan
+ */
+public class ArtifactInfo {
+ private final String groupId;
+ private final String artifactId;
+ private final String version;
+ private final String classfier;
+ private final String type;
+
+ public ArtifactInfo(String groupId, String artifactId, String version, String classfier, String type) {
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.version = version;
+ this.classfier = classfier;
+ this.type = type;
+ }
+
+ public String getGroupId() {
+ return groupId;
+ }
+
+ public String getArtifactId() {
+ return artifactId;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public String getClassfier() {
+ return classfier;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Constructs a <code>String</code> with all attributes
+ * in name = value format.
+ *
+ * @return a <code>String</code> representation
+ * of this object.
+ */
+ public String toString()
+ {
+ final String TAB = " "; //$NON-NLS-1$
+
+ String retValue = ""; //$NON-NLS-1$
+
+ retValue = "ArtifactInfo ( " //$NON-NLS-1$
+ + "groupId = " + this.groupId + TAB //$NON-NLS-1$
+ + "artifactId = " + this.artifactId + TAB //$NON-NLS-1$
+ + "version = " + this.version + TAB //$NON-NLS-1$
+ + "classfier = " + this.classfier + TAB //$NON-NLS-1$
+ + "type = " + this.type + TAB //$NON-NLS-1$
+ + " )"; //$NON-NLS-1$
+
+ return retValue;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/CComboContentAdapter.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/CComboContentAdapter.java
new file mode 100644
index 00000000..2dbbe432
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/CComboContentAdapter.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util.search;
+
+import org.eclipse.jface.fieldassist.ContentProposalAdapter;
+import org.eclipse.jface.fieldassist.IControlContentAdapter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+
+
+/**
+ * An {@link IControlContentAdapter} for SWT CCombo controls. This is a convenience class for easily creating a
+ * {@link ContentProposalAdapter} for combo fields.
+ */
+public class CComboContentAdapter implements IControlContentAdapter /*, IControlContentAdapter2 */ {
+
+ /*
+ * Set to <code>true</code> if we should compute the text
+ * vertical bounds rather than just use the field size.
+ * Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=164748
+ * The corresponding SWT bug is
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=44072
+ */
+ private static final boolean COMPUTE_TEXT_USING_CLIENTAREA = !"carbon".equals(SWT.getPlatform()); //$NON-NLS-1$
+
+ public String getControlContents(Control control) {
+ return ((CCombo) control).getText();
+ }
+
+ public void setControlContents(Control control, String text, int cursorPosition) {
+ ((CCombo) control).setText(text);
+ ((CCombo) control).setSelection(new Point(cursorPosition, cursorPosition));
+ }
+
+ public void insertControlContents(Control control, String text, int cursorPosition) {
+ CCombo combo = (CCombo) control;
+ String contents = combo.getText();
+ Point selection = combo.getSelection();
+ StringBuffer sb = new StringBuffer();
+ sb.append(contents.substring(0, selection.x));
+ sb.append(text);
+ if(selection.y < contents.length()) {
+ sb.append(contents.substring(selection.y, contents.length()));
+ }
+ combo.setText(sb.toString());
+ selection.x = selection.x + cursorPosition;
+ selection.y = selection.x;
+ combo.setSelection(selection);
+ }
+
+ public int getCursorPosition(Control control) {
+ return ((CCombo) control).getSelection().x;
+ }
+
+ public Rectangle getInsertionBounds(Control control) {
+ // This doesn't take horizontal scrolling into affect.
+ // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=204599
+ CCombo combo = (CCombo) control;
+ int position = combo.getSelection().y;
+ String contents = combo.getText();
+ GC gc = new GC(combo);
+ gc.setFont(combo.getFont());
+ Point extent = gc.textExtent(contents.substring(0, Math.min(position, contents.length())));
+ gc.dispose();
+ if(COMPUTE_TEXT_USING_CLIENTAREA) {
+ return new Rectangle(combo.getClientArea().x + extent.x, combo.getClientArea().y, 1, combo.getClientArea().height);
+ }
+ return new Rectangle(extent.x, 0, 1, combo.getSize().y);
+ }
+
+ public void setCursorPosition(Control control, int index) {
+ ((CCombo) control).setSelection(new Point(index, index));
+ }
+
+ public Point getSelection(Control control) {
+ return ((CCombo) control).getSelection();
+ }
+
+ public void setSelection(Control control, Point range) {
+ ((CCombo) control).setSelection(range);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/ControlDecoration.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/ControlDecoration.java
new file mode 100644
index 00000000..4e7b7fae
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/ControlDecoration.java
@@ -0,0 +1,1088 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+
+package org.eclipse.m2e.core.util.search;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.jface.fieldassist.FieldDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.graphics.Region;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Widget;
+
+
+/**
+ * ControlDecoration renders an image decoration near a control. It allows clients to specify an image and a position
+ * for the image relative to the control. A ControlDecoration may be assigned description text, which can optionally be
+ * shown when the user hovers over the image. Clients can decorate any kind of control.
+ * <p>
+ * Decoration images always appear on the left or right side of the field, never above or below it. Decorations can be
+ * positioned at the top, center, or bottom of either side of the control. Future implementations may provide additional
+ * positioning options for decorations.
+ * <p>
+ * ControlDecoration renders the image adjacent to the specified (already created) control, with no guarantee that it
+ * won't be clipped or otherwise obscured or overlapped by adjacent controls, including another ControlDecoration placed
+ * in the same location. Clients should ensure that there is adequate space adjacent to the control to show the
+ * decoration properly.
+ * <p>
+ * Clients using ControlDecoration should typically ensure that enough margin space is reserved for a decoration by
+ * altering the layout data margins, although this is not assumed or required by the ControlDecoration implementation.
+ * <p>
+ * This class is intended to be instantiated and used by clients. It is not intended to be subclassed by clients.
+ *
+ * @since 3.3
+ * @see FieldDecoration
+ * @see FieldDecorationRegistry
+ */
+public class ControlDecoration {
+ /**
+ * Debug flag for tracing
+ */
+ private static boolean DEBUG = false;
+
+ /**
+ * Cached platform flags for dealing with platform-specific issues.
+ */
+ static boolean CARBON = "carbon".equals(SWT.getPlatform()); //$NON-NLS-1$
+
+ /**
+ * The associated control
+ */
+ Control control;
+
+ /**
+ * The composite on which to render the decoration and hook mouse events, or null if we are hooking all parent
+ * composites.
+ */
+ private Composite composite;
+
+ /**
+ * The associated image.
+ */
+ private Image image;
+
+ /**
+ * The associated description text.
+ */
+ private String descriptionText;
+
+ /**
+ * The position of the decoration.
+ */
+ private int position;
+
+ /**
+ * The decoration's visibility flag
+ */
+ boolean visible = true;
+
+ /**
+ * Boolean indicating whether the decoration should only be shown when the control has focus
+ */
+ boolean showOnlyOnFocus = false;
+
+ /**
+ * Boolean indicating whether the decoration should show its description text in a hover when the user hovers over the
+ * decoration.
+ */
+ boolean showHover = true;
+
+ /**
+ * Margin width used between the decorator and the control.
+ */
+ private int marginWidth = 0;
+
+ /**
+ * Registered selection listeners.
+ */
+ ListenerList selectionListeners = new ListenerList();
+
+ /**
+ * Registered menu detect listeners.
+ */
+ ListenerList menuDetectListeners = new ListenerList();
+
+ /**
+ * The focus listener
+ */
+ private FocusListener focusListener;
+
+ /**
+ * The dispose listener
+ */
+ private DisposeListener disposeListener;
+
+ /**
+ * The paint listener installed for drawing the decoration
+ */
+ private PaintListener paintListener;
+
+ /**
+ * The mouse listener installed for tracking the hover
+ */
+ private MouseTrackListener mouseTrackListener;
+
+ /**
+ * The mouse move listener installed for tracking the hover
+ */
+ MouseMoveListener mouseMoveListener;
+
+ /**
+ * The untyped listener installed for notifying external listeners
+ */
+ private Listener compositeListener;
+
+ /**
+ * Control that we last installed a move listener on. We only want one at a time.
+ */
+ Control moveListeningTarget = null;
+
+ /**
+ * Debug counter used to match add and remove listeners
+ */
+ private int listenerInstalls = 0;
+
+ /**
+ * The current rectangle used for tracking mouse moves
+ */
+ Rectangle decorationRectangle;
+
+ /**
+ * An internal flag tracking whether we have focus. We use this rather than isFocusControl() so that we can set the
+ * flag as soon as we get the focus callback, rather than having to do an asyncExec in the middle of a focus callback
+ * to ensure that isFocusControl() represents the outcome of the event.
+ */
+ boolean hasFocus = false;
+
+ /**
+ * The hover used for showing description text
+ */
+ private Hover hover;
+
+ /**
+ * The hover used to show a decoration image's description.
+ */
+ class Hover {
+ private static final String EMPTY = ""; //$NON-NLS-1$
+
+ /**
+ * Offset of info hover arrow from the left or right side.
+ */
+ private int hao = 10;
+
+ /**
+ * Width of info hover arrow.
+ */
+ private int haw = 8;
+
+ /**
+ * Height of info hover arrow.
+ */
+ private int hah = 10;
+
+ /**
+ * Margin around info hover text.
+ */
+ int hm = 2;
+
+ /**
+ * This info hover's shell.
+ */
+ Shell hoverShell;
+
+ /**
+ * The info hover text.
+ */
+ String text = EMPTY;
+
+ /**
+ * The region used to manage the shell shape
+ */
+ Region region;
+
+ /**
+ * Boolean indicating whether the last computed polygon location had an arrow on left. (true if left, false if
+ * right).
+ */
+ boolean arrowOnLeft = true;
+
+ /*
+ * Create a hover parented by the specified shell.
+ */
+ Hover(Shell parent) {
+ final Display display = parent.getDisplay();
+ hoverShell = new Shell(parent, SWT.NO_TRIM | SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL);
+ hoverShell.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+ hoverShell.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
+ hoverShell.addPaintListener(new PaintListener() {
+ public void paintControl(PaintEvent pe) {
+ pe.gc.drawText(text, hm, hm);
+ if(!CARBON) {
+ pe.gc.drawPolygon(getPolygon(true));
+ }
+ }
+ });
+ hoverShell.addMouseListener(new MouseAdapter() {
+ public void mouseDown(MouseEvent e) {
+ hideHover();
+ }
+ });
+ }
+
+ /*
+ * Compute a polygon that represents a hover with an arrow pointer. If
+ * border is true, compute the polygon inset by 1-pixel border. Consult
+ * the arrowOnLeft flag to determine which side the arrow is on.
+ */
+ int[] getPolygon(boolean border) {
+ Point e = getExtent();
+ int b = border ? 1 : 0;
+ if(arrowOnLeft) {
+ return new int[] {0, 0, e.x - b, 0, e.x - b, e.y - b, hao + haw, e.y - b, hao + haw / 2, e.y + hah - b, hao,
+ e.y - b, 0, e.y - b, 0, 0};
+ }
+ return new int[] {0, 0, e.x - b, 0, e.x - b, e.y - b, e.x - hao - b, e.y - b, e.x - hao - haw / 2, e.y + hah - b,
+ e.x - hao - haw, e.y - b, 0, e.y - b, 0, 0};
+ }
+
+ /*
+ * Dispose the hover, it is no longer needed. Dispose any resources
+ * allocated by the hover.
+ */
+ void dispose() {
+ if(!hoverShell.isDisposed()) {
+ hoverShell.dispose();
+ }
+ if(region != null) {
+ region.dispose();
+ }
+ }
+
+ /*
+ * Set the visibility of the hover.
+ */
+ void setVisible(boolean visible) {
+ if(visible) {
+ if(!hoverShell.isVisible()) {
+ hoverShell.setVisible(true);
+ }
+ } else {
+ if(hoverShell.isVisible()) {
+ hoverShell.setVisible(false);
+ }
+ }
+ }
+
+ /*
+ * Set the text of the hover to the specified text. Recompute the size
+ * and location of the hover to hover near the decoration rectangle,
+ * pointing the arrow toward the target control.
+ */
+ void setText(String t, Rectangle decorationRectangle, Control targetControl) {
+ if(t == null) {
+ t = EMPTY;
+ }
+ if(!t.equals(text)) {
+ Point oldSize = getExtent();
+ text = t;
+ hoverShell.redraw();
+ Point newSize = getExtent();
+ if(!oldSize.equals(newSize)) {
+ // set a flag that indicates the direction of arrow
+ arrowOnLeft = decorationRectangle.x <= targetControl.getLocation().x;
+ setNewShape();
+ }
+ }
+
+ Point extent = getExtent();
+ int y = -extent.y - hah + 1;
+ int x = arrowOnLeft ? -hao + haw / 2 : -extent.x + hao + haw / 2;
+
+ hoverShell.setLocation(control.getParent().toDisplay(decorationRectangle.x + x, decorationRectangle.y + y));
+ }
+
+ /*
+ * Return whether or not the hover (shell) is visible.
+ */
+ boolean isVisible() {
+ return hoverShell.isVisible();
+ }
+
+ /*
+ * Compute the extent of the hover for the current text.
+ */
+ Point getExtent() {
+ GC gc = new GC(hoverShell);
+ Point e = gc.textExtent(text);
+ gc.dispose();
+ e.x += hm * 2;
+ e.y += hm * 2;
+ return e;
+ }
+
+ /*
+ * Compute a new shape for the hover shell.
+ */
+ void setNewShape() {
+ Region oldRegion = region;
+ region = new Region();
+ region.add(getPolygon(false));
+ hoverShell.setRegion(region);
+ if(oldRegion != null) {
+ oldRegion.dispose();
+ }
+
+ }
+ }
+
+ /**
+ * Construct a ControlDecoration for decorating the specified control at the specified position relative to the
+ * control. Render the decoration on top of any Control that happens to appear at the specified location.
+ * <p>
+ * SWT constants are used to specify the position of the decoration relative to the control. The position should
+ * include style bits describing both the vertical and horizontal orientation. <code>SWT.LEFT</code> and
+ * <code>SWT.RIGHT</code> describe the horizontal placement of the decoration relative to the control, and the
+ * constants <code>SWT.TOP</code>, <code>SWT.CENTER</code>, and <code>SWT.BOTTOM</code> describe the vertical
+ * alignment of the decoration relative to the control. Decorations always appear on either the left or right side of
+ * the control, never above or below it. For example, a decoration appearing on the left side of the field, at the
+ * top, is specified as SWT.LEFT | SWT.TOP. If no position style bits are specified, the control decoration will be
+ * positioned to the left and center of the control (<code>SWT.LEFT | SWT.CENTER</code>).
+ * </p>
+ *
+ * @param control the control to be decorated
+ * @param position bit-wise or of position constants (<code>SWT.TOP</code>, <code>SWT.BOTTOM</code>,
+ * <code>SWT.LEFT</code>, <code>SWT.RIGHT</code>, and <code>SWT.CENTER</code>).
+ */
+ public ControlDecoration(Control control, int position) {
+ this(control, position, null);
+
+ }
+
+ /**
+ * Construct a ControlDecoration for decorating the specified control at the specified position relative to the
+ * control. Render the decoration only on the specified Composite or its children. The decoration will be clipped if
+ * it does not appear within the visible bounds of the composite or its child composites.
+ * <p>
+ * SWT constants are used to specify the position of the decoration relative to the control. The position should
+ * include style bits describing both the vertical and horizontal orientation. <code>SWT.LEFT</code> and
+ * <code>SWT.RIGHT</code> describe the horizontal placement of the decoration relative to the control, and the
+ * constants <code>SWT.TOP</code>, <code>SWT.CENTER</code>, and <code>SWT.BOTTOM</code> describe the vertical
+ * alignment of the decoration relative to the control. Decorations always appear on either the left or right side of
+ * the control, never above or below it. For example, a decoration appearing on the left side of the field, at the
+ * top, is specified as SWT.LEFT | SWT.TOP. If no position style bits are specified, the control decoration will be
+ * positioned to the left and center of the control (<code>SWT.LEFT | SWT.CENTER</code>).
+ * </p>
+ *
+ * @param control the control to be decorated
+ * @param position bit-wise or of position constants (<code>SWT.TOP</code>, <code>SWT.BOTTOM</code>,
+ * <code>SWT.LEFT</code>, <code>SWT.RIGHT</code>, and <code>SWT.CENTER</code>).
+ * @param composite The SWT composite within which the decoration should be rendered. The decoration will be clipped
+ * to this composite, but it may be rendered on a child of the composite. The decoration will not be visible
+ * if the specified composite or its child composites are not visible in the space relative to the control,
+ * where the decoration is to be rendered. If this value is <code>null</code>, then the decoration will be
+ * rendered on whichever composite (or composites) are located in the specified position.
+ */
+ public ControlDecoration(Control control, int position, Composite composite) {
+ this.position = position;
+ this.control = control;
+ this.composite = composite;
+
+ addControlListeners();
+
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified when the platform-specific context menu
+ * trigger has occurred, by sending it one of the messages defined in the <code>MenuDetectListener</code> interface.
+ * <p>
+ * The <code>widget</code> field in the SelectionEvent will contain the Composite on which the decoration is rendered
+ * that received the click. The <code>x</code> and <code>y</code> fields will be in coordinates relative to the
+ * display. The <code>data</code> field will contain the decoration that received the event.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ * @see org.eclipse.swt.events.MenuDetectListener
+ * @see org.eclipse.swt.events.MenuDetectEvent
+ * @see #removeMenuDetectListener
+ */
+ public void addMenuDetectListener(MenuDetectListener listener) {
+ menuDetectListeners.add(listener);
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be notified when the platform-specific context menu
+ * trigger has occurred.
+ *
+ * @param listener the listener which should no longer be notified. This message has no effect if the listener was not
+ * previously added to the receiver.
+ * @see org.eclipse.swt.events.MenuDetectListener
+ * @see #addMenuDetectListener
+ */
+ public void removeMenuDetectListener(MenuDetectListener listener) {
+ menuDetectListeners.remove(listener);
+ }
+
+ /**
+ * Adds the listener to the collection of listeners who will be notified when the decoration is selected, by sending
+ * it one of the messages defined in the <code>SelectionListener</code> interface.
+ * <p>
+ * <code>widgetSelected</code> is called when the decoration is selected (by mouse click).
+ * <code>widgetDefaultSelected</code> is called when the decoration is double-clicked.
+ * </p>
+ * <p>
+ * The <code>widget</code> field in the SelectionEvent will contain the Composite on which the decoration is rendered
+ * that received the click. The <code>x</code> and <code>y</code> fields will be in coordinates relative to that
+ * widget. The <code>data</code> field will contain the decoration that received the event.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ * @see org.eclipse.swt.events.SelectionListener
+ * @see org.eclipse.swt.events.SelectionEvent
+ * @see #removeSelectionListener
+ */
+ public void addSelectionListener(SelectionListener listener) {
+ selectionListeners.add(listener);
+ }
+
+ /**
+ * Removes the listener from the collection of listeners who will be notified when the decoration is selected.
+ *
+ * @param listener the listener which should no longer be notified. This message has no effect if the listener was not
+ * previously added to the receiver.
+ * @see org.eclipse.swt.events.SelectionListener
+ * @see #addSelectionListener
+ */
+ public void removeSelectionListener(SelectionListener listener) {
+ selectionListeners.remove(listener);
+ }
+
+ /**
+ * Dispose this ControlDecoration. Unhook any listeners that have been installed on the target control. This method
+ * has no effect if the receiver is already disposed.
+ */
+ public void dispose() {
+ if(control == null) {
+ return;
+ }
+ if(hover != null) {
+ hover.dispose();
+ hover = null;
+ }
+ removeControlListeners();
+ control = null;
+ }
+
+ /**
+ * Get the control that is decorated by the receiver.
+ *
+ * @return the Control decorated by the receiver. May be <code>null</code> if the control has been uninstalled.
+ */
+ public Control getControl() {
+ return control;
+ }
+
+ /**
+ * Add any listeners needed on the target control and on the composite where the decoration is to be rendered.
+ */
+ private void addControlListeners() {
+ disposeListener = new DisposeListener() {
+ public void widgetDisposed(DisposeEvent event) {
+ dispose();
+ }
+ };
+ printAddListener(control, "DISPOSE"); //$NON-NLS-1$
+ control.addDisposeListener(disposeListener);
+
+ focusListener = new FocusListener() {
+ public void focusGained(FocusEvent event) {
+ hasFocus = true;
+ if(showOnlyOnFocus) {
+ update();
+ }
+ }
+
+ public void focusLost(FocusEvent event) {
+ hasFocus = false;
+ if(showOnlyOnFocus) {
+ update();
+ }
+ }
+ };
+ printAddListener(control, "FOCUS"); //$NON-NLS-1$
+ control.addFocusListener(focusListener);
+
+ // Listener for painting the decoration
+ paintListener = new PaintListener() {
+ public void paintControl(PaintEvent event) {
+ Control control = (Control) event.widget;
+ Rectangle rect = getDecorationRectangle(control);
+ if(shouldShowDecoration()) {
+ event.gc.drawImage(getImage(), rect.x, rect.y);
+ }
+ }
+ };
+
+ // Listener for tracking the end of a hover. Only installed
+ // after a hover begins.
+ mouseMoveListener = new MouseMoveListener() {
+ public void mouseMove(MouseEvent event) {
+ if(showHover) {
+ if(!decorationRectangle.contains(event.x, event.y)) {
+ hideHover();
+ // No need to listen any longer
+ printRemoveListener(event.widget, "MOUSEMOVE"); //$NON-NLS-1$
+ ((Control) event.widget).removeMouseMoveListener(mouseMoveListener);
+ moveListeningTarget = null;
+ }
+ }
+ }
+ };
+
+ // Listener for tracking the beginning of a hover. Always installed.
+ mouseTrackListener = new MouseTrackListener() {
+ public void mouseExit(MouseEvent event) {
+ // Just in case we didn't catch it before.
+ Control target = (Control) event.widget;
+ if(target == moveListeningTarget) {
+ printRemoveListener(target, "MOUSEMOVE"); //$NON-NLS-1$
+ target.removeMouseMoveListener(mouseMoveListener);
+ moveListeningTarget = null;
+ }
+ hideHover();
+ }
+
+ public void mouseHover(MouseEvent event) {
+ if(showHover) {
+ decorationRectangle = getDecorationRectangle((Control) event.widget);
+ if(decorationRectangle.contains(event.x, event.y)) {
+ showHoverText(getDescriptionText());
+ Control target = (Control) event.widget;
+ if(moveListeningTarget == null) {
+ printAddListener(target, "MOUSEMOVE"); //$NON-NLS-1$
+ target.addMouseMoveListener(mouseMoveListener);
+ moveListeningTarget = target;
+ } else if(target != moveListeningTarget) {
+ printRemoveListener(moveListeningTarget, "MOUSEMOVE"); //$NON-NLS-1$
+ moveListeningTarget.removeMouseMoveListener(mouseMoveListener);
+ printAddListener(target, "MOUSEMOVE"); //$NON-NLS-1$
+ target.addMouseMoveListener(mouseMoveListener);
+ moveListeningTarget = target;
+ } else {
+ // It is already installed on this control.
+ }
+ }
+ }
+ }
+
+ public void mouseEnter(MouseEvent event) {
+ // Nothing to do until a hover occurs.
+ }
+ };
+
+ compositeListener = new Listener() {
+ public void handleEvent(Event event) {
+ // Don't forward events if decoration is not showing
+ if(!visible) {
+ return;
+ }
+ // Notify listeners if any are registered.
+ switch(event.type) {
+ case SWT.MouseDown:
+ if(!selectionListeners.isEmpty())
+ notifySelectionListeners(event);
+ break;
+ case SWT.MouseDoubleClick:
+ if(!selectionListeners.isEmpty())
+ notifySelectionListeners(event);
+ break;
+ case SWT.MenuDetect:
+ if(!menuDetectListeners.isEmpty())
+ notifyMenuDetectListeners(event);
+ break;
+ }
+ }
+ };
+
+ // We do not know which parent in the control hierarchy
+ // is providing the decoration space, so hook all the way up, until
+ // the shell or the specified parent composite is reached.
+ Composite c = control.getParent();
+ while(c != null) {
+ installCompositeListeners(c);
+ if(composite != null && composite == c) {
+ // We just installed on the specified composite, so stop.
+ c = null;
+ } else if(c instanceof Shell) {
+ // We just installed on a shell, so don't go further
+ c = null;
+ } else {
+ c = c.getParent();
+ }
+ }
+ // force a redraw of the decoration area so our paint listener
+ // is notified.
+ update();
+ }
+
+ /*
+ * Install the listeners used to paint and track mouse events on the
+ * composite.
+ */
+ private void installCompositeListeners(Composite c) {
+ if(!c.isDisposed()) {
+ printAddListener(c, "PAINT"); //$NON-NLS-1$
+ c.addPaintListener(paintListener);
+ printAddListener(c, "MOUSETRACK"); //$NON-NLS-1$
+ c.addMouseTrackListener(mouseTrackListener);
+ printAddListener(c, "SWT.MenuDetect"); //$NON-NLS-1$
+ c.addListener(SWT.MenuDetect, compositeListener);
+ printAddListener(c, "SWT.MouseDown"); //$NON-NLS-1$
+ c.addListener(SWT.MouseDown, compositeListener);
+ printAddListener(c, "SWT.MouseDoubleClick"); //$NON-NLS-1$
+ c.addListener(SWT.MouseDoubleClick, compositeListener);
+ }
+ }
+
+ /*
+ * Remove the listeners used to paint and track mouse events on the
+ * composite.
+ */
+ private void removeCompositeListeners(Composite c) {
+ if(!c.isDisposed()) {
+ printRemoveListener(c, "PAINT"); //$NON-NLS-1$
+ c.removePaintListener(paintListener);
+ printRemoveListener(c, "MOUSETRACK"); //$NON-NLS-1$
+ c.removeMouseTrackListener(mouseTrackListener);
+ printRemoveListener(c, "SWT.MenuDetect"); //$NON-NLS-1$
+ c.removeListener(SWT.MenuDetect, compositeListener);
+ printRemoveListener(c, "SWT.MouseDown"); //$NON-NLS-1$
+ c.removeListener(SWT.MouseDown, compositeListener);
+ printRemoveListener(c, "SWT.MouseDoubleClick"); //$NON-NLS-1$
+ c.removeListener(SWT.MouseDoubleClick, compositeListener);
+ }
+ }
+
+ void notifySelectionListeners(Event event) {
+ if(!(event.widget instanceof Control)) {
+ return;
+ }
+ if(getDecorationRectangle((Control) event.widget).contains(event.x, event.y)) {
+ SelectionEvent clientEvent = new SelectionEvent(event);
+ clientEvent.data = this;
+ if(getImage() != null) {
+ clientEvent.height = getImage().getBounds().height;
+ clientEvent.width = getImage().getBounds().width;
+ }
+ Object[] listeners;
+ switch(event.type) {
+ case SWT.MouseDoubleClick:
+ if(event.button == 1) {
+ listeners = selectionListeners.getListeners();
+ for(int i = 0; i < listeners.length; i++ ) {
+ ((SelectionListener) listeners[i]).widgetDefaultSelected(clientEvent);
+ }
+ }
+ break;
+ case SWT.MouseDown:
+ if(event.button == 1) {
+ listeners = selectionListeners.getListeners();
+ for(int i = 0; i < listeners.length; i++ ) {
+ ((SelectionListener) listeners[i]).widgetSelected(clientEvent);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ void notifyMenuDetectListeners(Event event) {
+ if(getDecorationRectangle(null).contains(event.x, event.y)) {
+ MenuDetectEvent clientEvent = new MenuDetectEvent(event);
+ clientEvent.data = this;
+ Object[] listeners = menuDetectListeners.getListeners();
+ for(int i = 0; i < listeners.length; i++ ) {
+ ((MenuDetectListener) listeners[i]).menuDetected(clientEvent);
+
+ }
+ }
+ }
+
+ /**
+ * Show the specified text using the same hover dialog as is used to show decorator descriptions. When
+ * {@link #setShowHover(boolean)} has been set to <code>true</code>, a decoration's description text will be shown in
+ * an info hover over the field's control whenever the mouse hovers over the decoration. This method can be used to
+ * show a decoration's description text at other times (such as when the control receives focus), or to show other
+ * text associated with the field. The hover will not be shown if the decoration is hidden.
+ *
+ * @param text the text to be shown in the info hover, or <code>null</code> if no text should be shown.
+ */
+ public void showHoverText(String text) {
+ if(control == null) {
+ return;
+ }
+ showHoverText(text, control);
+ }
+
+ /**
+ * Hide any hover popups that are currently showing on the control. When {@link #setShowHover(boolean)} has been set
+ * to <code>true</code>, a decoration's description text will be shown in an info hover over the field's control as
+ * long as the mouse hovers over the decoration, and will be hidden when the mouse exits the decoration. This method
+ * can be used to hide a hover, whether it was shown explicitly using {@link #showHoverText(String)}, or was showing
+ * because the user was hovering in the decoration.
+ * <p>
+ * This message has no effect if there is no current hover.
+ */
+ public void hideHover() {
+ if(hover != null) {
+ hover.setVisible(false);
+ }
+ }
+
+ /**
+ * Show the control decoration. This message has no effect if the decoration is already showing. If
+ * {@link #setShowOnlyOnFocus(boolean)} is set to <code>true</code>, the decoration will only be shown if the control
+ * has focus.
+ */
+ public void show() {
+ if(!visible) {
+ visible = true;
+ update();
+ }
+ }
+
+ /**
+ * Hide the control decoration and any associated hovers. This message has no effect if the decoration is already
+ * hidden.
+ */
+ public void hide() {
+ if(visible) {
+ visible = false;
+ hideHover();
+ update();
+ }
+ }
+
+ /**
+ * Get the description text that may be shown in a hover for this decoration.
+ *
+ * @return the text to be shown as a description for the decoration, or <code>null</code> if none has been set.
+ */
+ public String getDescriptionText() {
+ return descriptionText;
+ }
+
+ /**
+ * Set the image shown in this control decoration. Update the rendered decoration.
+ *
+ * @param text the text to be shown as a description for the decoration, or <code>null</code> if none has been set.
+ */
+ public void setDescriptionText(String text) {
+ this.descriptionText = text;
+ update();
+ }
+
+ /**
+ * Get the image shown in this control decoration.
+ *
+ * @return the image to be shown adjacent to the control, or <code>null</code> if one has not been set.
+ */
+ public Image getImage() {
+ return image;
+ }
+
+ /**
+ * Set the image shown in this control decoration. Update the rendered decoration.
+ *
+ * @param image the image to be shown adjacent to the control. Should never be <code>null</code>.
+ */
+ public void setImage(Image image) {
+ this.image = image;
+ update();
+ }
+
+ /**
+ * Get the boolean that controls whether the decoration is shown only when the control has focus. The default value of
+ * this setting is <code>false</code>.
+ *
+ * @return <code>true</code> if the decoration should only be shown when the control has focus, and <code>false</code>
+ * if it should always be shown. Note that if the control is not capable of receiving focus (
+ * <code>SWT.NO_FOCUS</code>), then the decoration will never show when this value is <code>true</code>.
+ */
+ public boolean getShowOnlyOnFocus() {
+ return showOnlyOnFocus;
+ }
+
+ /**
+ * Set the boolean that controls whether the decoration is shown only when the control has focus. The default value of
+ * this setting is <code>false</code>.
+ *
+ * @param showOnlyOnFocus <code>true</code> if the decoration should only be shown when the control has focus, and
+ * <code>false</code> if it should always be shown. Note that if the control is not capable of receiving
+ * focus (<code>SWT.NO_FOCUS</code>), then the decoration will never show when this value is
+ * <code>true</code>.
+ */
+ public void setShowOnlyOnFocus(boolean showOnlyOnFocus) {
+ this.showOnlyOnFocus = showOnlyOnFocus;
+ update();
+ }
+
+ /**
+ * Get the boolean that controls whether the decoration's description text should be shown in a hover when the user
+ * hovers over the decoration. The default value of this setting is <code>true</code>.
+ *
+ * @return <code>true</code> if a hover popup containing the decoration's description text should be shown when the
+ * user hovers over the decoration, and <code>false</code> if a hover should not be shown.
+ */
+ public boolean getShowHover() {
+ return showHover;
+ }
+
+ /**
+ * Set the boolean that controls whether the decoration's description text should be shown in a hover when the user
+ * hovers over the decoration. The default value of this setting is <code>true</code>.
+ *
+ * @param showHover <code>true</code> if a hover popup containing the decoration's description text should be shown
+ * when the user hovers over the decoration, and <code>false</code> if a hover should not be shown.
+ */
+ public void setShowHover(boolean showHover) {
+ this.showHover = showHover;
+ update();
+ }
+
+ /**
+ * Get the margin width in pixels that should be used between the decorator and the horizontal edge of the control.
+ * The default value of this setting is <code>0</code>.
+ *
+ * @return the number of pixels that should be reserved between the horizontal edge of the control and the adjacent
+ * edge of the decoration.
+ */
+ public int getMarginWidth() {
+ return marginWidth;
+ }
+
+ /**
+ * Set the margin width in pixels that should be used between the decorator and the horizontal edge of the control.
+ * The default value of this setting is <code>0</code>.
+ *
+ * @param marginWidth the number of pixels that should be reserved between the horizontal edge of the control and the
+ * adjacent edge of the decoration.
+ */
+ public void setMarginWidth(int marginWidth) {
+ this.marginWidth = marginWidth;
+ update();
+ }
+
+ /**
+ * Something has changed, requiring redraw. Redraw the decoration and update the hover text if appropriate.
+ */
+ protected void update() {
+ if(control == null || control.isDisposed()) {
+ return;
+ }
+ Rectangle rect = getDecorationRectangle(control.getShell());
+ // Redraw this rectangle in all children
+ control.getShell().redraw(rect.x, rect.y, rect.width, rect.height, true);
+ control.getShell().update();
+ if(hover != null && getDescriptionText() != null) {
+ hover.setText(getDescriptionText(), getDecorationRectangle(control.getParent()), control);
+ }
+ }
+
+ /*
+ * Show the specified text in the hover, positioning the hover near the
+ * specified control.
+ */
+ private void showHoverText(String text, Control hoverNear) {
+ // If we aren't to show a hover, don't do anything.
+ if(!showHover) {
+ return;
+ }
+
+ // If we are not visible, don't show the hover.
+ if(!visible) {
+ return;
+ }
+ // If there is no text, don't do anything.
+ if(text == null) {
+ hideHover();
+ return;
+ }
+
+ // If there is no control, nothing to do
+ if(control == null) {
+ return;
+ }
+ // Create the hover if it's not showing
+ if(hover == null) {
+ hover = new Hover(hoverNear.getShell());
+ }
+ hover.setText(text, getDecorationRectangle(control.getParent()), control);
+ hover.setVisible(true);
+ }
+
+ /*
+ * Remove any listeners installed on the controls.
+ */
+ private void removeControlListeners() {
+ if(control == null) {
+ return;
+ }
+ printRemoveListener(control, "FOCUS"); //$NON-NLS-1$
+ control.removeFocusListener(focusListener);
+ focusListener = null;
+
+ printRemoveListener(control, "DISPOSE"); //$NON-NLS-1$
+ control.removeDisposeListener(disposeListener);
+ disposeListener = null;
+
+ Composite c = control.getParent();
+ while(c != null) {
+ removeCompositeListeners(c);
+ if(composite != null && composite == c) {
+ // We previously installed listeners only to the specified
+ // composite, so stop.
+ c = null;
+ } else if(c instanceof Shell) {
+ // We previously installed listeners only up to the first Shell
+ // encountered, so stop.
+ c = null;
+ } else {
+ c = c.getParent();
+ }
+ }
+ paintListener = null;
+ mouseTrackListener = null;
+ compositeListener = null;
+
+ // We may have a remaining mouse move listener installed
+ if(moveListeningTarget != null) {
+ printRemoveListener(moveListeningTarget, "MOUSEMOVE"); //$NON-NLS-1$
+ moveListeningTarget.removeMouseMoveListener(mouseMoveListener);
+ moveListeningTarget = null;
+ mouseMoveListener = null;
+ }
+ if(DEBUG) {
+ if(listenerInstalls > 0) {
+ System.out.println("LISTENER LEAK>>>CHECK TRACE ABOVE"); //$NON-NLS-1$
+ } else if(listenerInstalls < 0) {
+ System.out.println("REMOVED UNREGISTERED LISTENERS>>>CHECK TRACE ABOVE"); //$NON-NLS-1$
+ } else {
+ System.out.println("ALL INSTALLED LISTENERS WERE REMOVED."); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Return the rectangle in which the decoration should be rendered, in coordinates relative to the specified control.
+ * If the specified control is null, return the rectangle in display coordinates.
+ *
+ * @param targetControl the control whose coordinates should be used
+ * @return the rectangle in which the decoration should be rendered
+ */
+ protected Rectangle getDecorationRectangle(Control targetControl) {
+ if(getImage() == null || control == null) {
+ return new Rectangle(0, 0, 0, 0);
+ }
+ // Compute the bounds first relative to the control's parent.
+ Rectangle imageBounds = getImage().getBounds();
+ Rectangle controlBounds = control.getBounds();
+ int x, y;
+ // Compute x
+ if((position & SWT.RIGHT) == SWT.RIGHT) {
+ x = controlBounds.x + controlBounds.width + marginWidth;
+ } else {
+ // default is left
+ x = controlBounds.x - imageBounds.width - marginWidth;
+ }
+ // Compute y
+ if((position & SWT.TOP) == SWT.TOP) {
+ y = controlBounds.y;
+ } else if((position & SWT.BOTTOM) == SWT.BOTTOM) {
+ y = controlBounds.y + control.getBounds().height - imageBounds.height;
+ } else {
+ // default is center
+ y = controlBounds.y + (control.getBounds().height - imageBounds.height) / 2;
+ }
+
+ // Now convert to coordinates relative to the target control.
+ Point globalPoint = control.getParent().toDisplay(x, y);
+ Point targetPoint;
+ if(targetControl == null) {
+ targetPoint = globalPoint;
+ } else {
+ targetPoint = targetControl.toControl(globalPoint);
+ }
+ return new Rectangle(targetPoint.x, targetPoint.y, imageBounds.width, imageBounds.height);
+ }
+
+ /*
+ * Return true if the decoration should be shown, false if it should not.
+ */
+ boolean shouldShowDecoration() {
+ if(!visible) {
+ return false;
+ }
+ if(control == null || control.isDisposed() || getImage() == null) {
+ return false;
+ }
+
+ if(!control.isVisible()) {
+ return false;
+ }
+ if(showOnlyOnFocus) {
+ return hasFocus;
+ }
+ return true;
+ }
+
+ /*
+ * If in debug mode, print info about adding the specified listener.
+ */
+ void printAddListener(Widget widget, String listenerType) {
+ listenerInstalls++ ;
+ if(DEBUG) {
+ System.out.println("Added listener>>>" + listenerType + " to>>>" + widget); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ }
+
+ /*
+ * If in debug mode, print info about adding the specified listener.
+ */
+ void printRemoveListener(Widget widget, String listenerType) {
+ listenerInstalls-- ;
+ if(DEBUG) {
+ System.out.println("Removed listener>>>" + listenerType + " from>>>" + widget); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/IndexSearchEngine.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/IndexSearchEngine.java
new file mode 100644
index 00000000..6ac3717b
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/IndexSearchEngine.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util.search;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.apache.maven.artifact.versioning.ComparableVersion;
+
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexManager;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.index.MatchTyped.MatchType;
+import org.eclipse.m2e.core.index.MatchTypedStringSearchExpression;
+import org.eclipse.m2e.core.index.SearchExpression;
+
+
+/**
+ * Search engine integrating {@link IndexManager} with POM XML editor.
+ *
+ * @author Lukas Krecan
+ * @author Eugene Kuleshov
+ */
+public class IndexSearchEngine implements SearchEngine {
+
+ private final IIndex index;
+
+ public IndexSearchEngine(IIndex index) {
+ this.index = index;
+ }
+
+ protected boolean isBlank(String str) {
+ return str == null || str.trim().length() == 0;
+ }
+
+ public Collection<String> findArtifactIds(String groupId, String searchExpression, Packaging packaging,
+ ArtifactInfo containingArtifact) {
+ // TODO add support for implicit groupIds in plugin dependencies "org.apache.maven.plugins", ...
+ // Someone, give me here access to settings.xml, to be able to pick up "real" predefined groupIds added by user
+ // Currently, I am just simulating the "factory defaults" of maven, but user changes to settings.xml
+ // will not be picked up this way!
+ ArrayList<SearchExpression> groupIdSearchExpressions = new ArrayList<SearchExpression>();
+ if(isBlank(groupId)) {
+ // values from effective settings
+ // we are wiring in the defaults only, but user changes are lost!
+ // org.apache.maven.plugins
+ // org.codehaus.mojo
+ groupIdSearchExpressions.add(new MatchTypedStringSearchExpression("org.apache.maven.plugins", MatchType.EXACT));
+ groupIdSearchExpressions.add(new MatchTypedStringSearchExpression("org.codehaus.mojo", MatchType.EXACT));
+ } else {
+ groupIdSearchExpressions.add(new MatchTypedStringSearchExpression(groupId, MatchType.EXACT));
+ }
+
+ try {
+ TreeSet<String> ids = new TreeSet<String>();
+ for(IndexedArtifact artifact : index.find(groupIdSearchExpressions, null, null,
+ Collections.singleton(packaging.toSearchExpression()))) {
+ ids.add(artifact.getArtifactId());
+ }
+ return subSet(ids, searchExpression);
+ } catch(CoreException ex) {
+ throw new SearchException(ex.getMessage(), ex.getStatus().getException());
+ }
+ }
+
+ public Collection<String> findClassifiers(String groupId, String artifactId, String version, String prefix,
+ Packaging packaging) {
+ try {
+ Collection<IndexedArtifact> values = index.find(new MatchTypedStringSearchExpression(groupId, MatchType.EXACT),
+ new MatchTypedStringSearchExpression(artifactId, MatchType.EXACT), null, packaging.toSearchExpression());
+ if(values.isEmpty()) {
+ return Collections.emptySet();
+ }
+
+ TreeSet<String> ids = new TreeSet<String>();
+ Set<IndexedArtifactFile> files = values.iterator().next().getFiles();
+ for(IndexedArtifactFile artifactFile : files) {
+ if(artifactFile.classifier != null) {
+ ids.add(artifactFile.classifier);
+ }
+ }
+ return subSet(ids, prefix);
+ } catch(CoreException ex) {
+ throw new SearchException(ex.getMessage(), ex.getStatus().getException());
+ }
+ }
+
+ public Collection<String> findGroupIds(String searchExpression, Packaging packaging, ArtifactInfo containingArtifact) {
+ try {
+ TreeSet<String> ids = new TreeSet<String>();
+
+ SearchExpression groupSearchExpression = isBlank(searchExpression) ? null : new MatchTypedStringSearchExpression(
+ searchExpression, MatchType.PARTIAL);
+
+ for(IndexedArtifact artifact : index.find(groupSearchExpression, null, null, packaging.toSearchExpression())) {
+ ids.add(artifact.getGroupId());
+ }
+ return subSet(ids, searchExpression);
+ } catch(CoreException ex) {
+ throw new SearchException(ex.getMessage(), ex.getStatus().getException());
+ }
+ }
+
+ public Collection<String> findTypes(String groupId, String artifactId, String version, String prefix,
+ Packaging packaging) {
+ try {
+ Collection<IndexedArtifact> values = index.find(new MatchTypedStringSearchExpression(groupId, MatchType.EXACT),
+ new MatchTypedStringSearchExpression(artifactId, MatchType.EXACT), null, packaging.toSearchExpression());
+ if(values.isEmpty()) {
+ return Collections.emptySet();
+ }
+
+ TreeSet<String> ids = new TreeSet<String>();
+ Set<IndexedArtifactFile> files = values.iterator().next().getFiles();
+ for(IndexedArtifactFile artifactFile : files) {
+ if(artifactFile.type != null) {
+ ids.add(artifactFile.type);
+ }
+ }
+ return subSet(ids, prefix);
+ } catch(CoreException ex) {
+ throw new SearchException(ex.getMessage(), ex.getStatus().getException());
+ }
+ }
+
+ public Collection<String> findVersions(String groupId, String artifactId, String searchExpression, Packaging packaging) {
+ try {
+ Collection<IndexedArtifact> values = index.find(new MatchTypedStringSearchExpression(groupId, MatchType.EXACT),
+ new MatchTypedStringSearchExpression(artifactId, MatchType.EXACT), null, packaging.toSearchExpression());
+ if(values.isEmpty()) {
+ return Collections.emptySet();
+ }
+
+ TreeSet<String> ids = new TreeSet<String>();
+ Set<IndexedArtifactFile> files = values.iterator().next().getFiles();
+ for(IndexedArtifactFile artifactFile : files) {
+ ids.add(artifactFile.version);
+ }
+ Collection<String> result = subSet(ids, searchExpression);
+
+ // sort results according to o.a.m.artifact.versioning.ComparableVersion
+ SortedSet<ComparableVersion> versions = new TreeSet<ComparableVersion>();
+ for(String version : result) {
+ versions.add(new ComparableVersion(version));
+ }
+ result = null; // not used any more
+ List<String> sorted = new ArrayList<String>(versions.size());
+ for(ComparableVersion version : versions) {
+ sorted.add(version.toString());
+ }
+ versions = null; // not used any more
+ Collections.reverse(sorted);
+ return sorted;
+ } catch(CoreException ex) {
+ throw new SearchException(ex.getMessage(), ex.getStatus().getException());
+ }
+ }
+
+ private Collection<String> subSet(TreeSet<String> ids, String searchExpression) {
+ if(searchExpression == null || searchExpression.length() == 0) {
+ return ids;
+ }
+ int n = searchExpression.length();
+ return ids.subSet(searchExpression, //
+ searchExpression.substring(0, n - 1) + ((char) (searchExpression.charAt(n - 1) + 1)));
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/MenuDetectEvent.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/MenuDetectEvent.java
new file mode 100644
index 00000000..95d976b5
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/MenuDetectEvent.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util.search;
+
+
+import org.eclipse.swt.events.TypedEvent;
+import org.eclipse.swt.widgets.Event;
+
+/**
+ * Instances of this class are sent whenever the platform-
+ * specific trigger for showing a context menu is detected.
+ *
+ * @see MenuDetectListener
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.3
+ */
+
+public final class MenuDetectEvent extends TypedEvent {
+
+ /**
+ * the display-relative x coordinate of the pointer
+ * at the time the context menu trigger occurred
+ */
+ public int x;
+
+ /**
+ * the display-relative y coordinate of the pointer
+ * at the time the context menu trigger occurred
+ */
+ public int y;
+
+ /**
+ * A flag indicating whether the operation should be allowed.
+ * Setting this field to <code>false</code> will cancel the operation.
+ */
+ public boolean doit;
+
+ private static final long serialVersionUID = -3061660596590828941L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public MenuDetectEvent(Event e) {
+ super(e);
+ this.x = e.x;
+ this.y = e.y;
+ this.doit = e.doit;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " x=" + x //$NON-NLS-1$
+ + " y=" + y //$NON-NLS-1$
+ + " doit=" + doit //$NON-NLS-1$
+ + "}"; //$NON-NLS-1$
+}
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/MenuDetectListener.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/MenuDetectListener.java
new file mode 100644
index 00000000..4de16ce7
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/MenuDetectListener.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util.search;
+
+
+import java.util.EventListener;
+
+/**
+ * Classes which implement this interface provide methods
+ * that deal with the events that are generated when the
+ * platform-specific trigger for showing a context menu is
+ * detected.
+ * <p>
+ * After creating an instance of a class that implements
+ * this interface it can be added to a control or TrayItem
+ * using the <code>addMenuDetectListener</code> method and
+ * removed using the <code>removeMenuDetectListener</code> method.
+ * When the context menu trigger occurs, the
+ * <code>menuDetected</code> method will be invoked.
+ * </p>
+ *
+ * @see MenuDetectEvent
+ *
+ * @since 3.3
+ */
+public interface MenuDetectListener extends EventListener {
+
+/**
+ * Sent when the platform-dependent trigger for showing a menu item is detected.
+ *
+ * @param e an event containing information about the menu detect
+ */
+public void menuDetected (MenuDetectEvent e);
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/Packaging.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/Packaging.java
new file mode 100644
index 00000000..52f92101
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/Packaging.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util.search;
+
+import org.eclipse.m2e.core.index.SearchExpression;
+import org.eclipse.m2e.core.index.SourcedSearchExpression;
+
+
+/**
+ * Packaging representation.
+ *
+ * @author Lukas Krecan
+ */
+public enum Packaging {
+ ALL(null), PLUGIN("maven-plugin"), // //$NON-NLS-1$
+ POM("pom"); //$NON-NLS-1$
+
+ private final String text;
+
+ private Packaging(String text) {
+ this.text = text;
+ }
+
+ /**
+ * Text representation of the packaging.
+ */
+ public String getText() {
+ return text;
+ }
+
+ public SearchExpression toSearchExpression() {
+ if(ALL.equals(this)) {
+ return null;
+ }
+
+ return new SourcedSearchExpression(getText());
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/SearchEngine.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/SearchEngine.java
new file mode 100644
index 00000000..9490a7e7
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/SearchEngine.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util.search;
+
+import java.util.Collection;
+
+
+/**
+ * Interface to be implemented by a SearchEngine.
+ *
+ * @author Lukas Krecan
+ */
+public interface SearchEngine {
+
+ /**
+ * Finds groupIds for given expression.
+ * @param searchExpression
+ * @param packaging
+ * @param containingArtifact When looking for exclusion, contains information about artifact we are excluding from.
+ * @return
+ */
+ public Collection<String> findGroupIds(String searchExpression, Packaging packaging, ArtifactInfo containingArtifact);
+
+ /**
+ * Finds artifactIds for given expression
+ * @param groupId
+ * @param searchExpression
+ * @param packaging
+ * @param containingArtifact When looking for exclusion, contains information about artifact we are excluding from.
+ * @return
+ */
+ public Collection<String> findArtifactIds(String groupId, String searchExpression, Packaging packaging, ArtifactInfo containingArtifact);
+
+ public Collection<String> findVersions(String groupId, String artifactId, String searchExpression, Packaging packaging);
+
+ public Collection<String> findClassifiers(String groupId, String artifactId, String version, String prefix, Packaging packaging);
+
+ public Collection<String> findTypes(String groupId, String artifactId, String version, String prefix, Packaging packaging);
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/SearchException.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/SearchException.java
new file mode 100644
index 00000000..606836ed
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/util/search/SearchException.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.util.search;
+
+/**
+ * @author Lukas Krecan
+ */
+public class SearchException extends RuntimeException {
+
+ private static final long serialVersionUID = 6909305234190388928L;
+
+ public SearchException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public SearchException(String message) {
+ super(message);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/AbstractMavenWizardPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/AbstractMavenWizardPage.java
new file mode 100644
index 00000000..cac68318
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/AbstractMavenWizardPage.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+
+
+/**
+ * AbstractMavenImportWizardPage
+ *
+ * @author Eugene Kuleshov
+ */
+public abstract class AbstractMavenWizardPage extends WizardPage {
+
+ /** the history limit */
+ protected static final int MAX_HISTORY = 15;
+
+ /**
+ * The project import configuration
+ */
+ private ProjectImportConfiguration importConfiguration;
+
+ /** The resolver configuration panel */
+ protected ResolverConfigurationComponent resolverConfigurationComponent;
+
+ /** dialog settings to store input history */
+ protected IDialogSettings dialogSettings;
+
+ /** the Map of field ids to List of comboboxes that share the same history */
+ private Map<String, List<Combo>> fieldsWithHistory;
+
+ private boolean isHistoryLoaded = false;
+
+ /** @wbp.parser.constructor */
+ protected AbstractMavenWizardPage(String pageName) {
+ this(pageName, null);
+ }
+
+ /**
+ * Creates a page. This constructor should be used for the wizards where you need to have the advanced settings box on
+ * each page. Pass the same bean to each page so they can share the data.
+ */
+ protected AbstractMavenWizardPage(String pageName, ProjectImportConfiguration importConfiguration) {
+ super(pageName);
+ this.importConfiguration = importConfiguration;
+
+ fieldsWithHistory = new HashMap<String, List<Combo>>();
+
+ initDialogSettings();
+ }
+
+ public ProjectImportConfiguration getImportConfiguration() {
+ return this.importConfiguration;
+ }
+
+ /** Creates an advanced settings panel. */
+ protected void createAdvancedSettings(Composite composite, GridData gridData) {
+ if(importConfiguration != null) {
+// Label separator = new Label(composite, SWT.HORIZONTAL | SWT.SEPARATOR);
+// GridData separatorData = new GridData(SWT.FILL, SWT.TOP, false, false, gridData.horizontalSpan, 1);
+// separatorData.verticalIndent = 7;
+// separator.setLayoutData(separatorData);
+ gridData.verticalIndent = 7;
+
+ resolverConfigurationComponent = new ResolverConfigurationComponent(composite, importConfiguration, true);
+ resolverConfigurationComponent.setLayoutData(gridData);
+ addFieldWithHistory("projectNameTemplate", resolverConfigurationComponent.template); //$NON-NLS-1$
+ }
+ }
+
+ /** Loads the advanced settings data when the page is displayed. */
+ public void setVisible(boolean visible) {
+ if(visible) {
+ if(!isHistoryLoaded) {
+ // load data before history kicks in
+ if(resolverConfigurationComponent != null) {
+ resolverConfigurationComponent.loadData();
+ }
+ loadInputHistory();
+ isHistoryLoaded = true;
+ } else {
+ saveInputHistory();
+ }
+ if(resolverConfigurationComponent != null) {
+ resolverConfigurationComponent.loadData();
+ }
+ }
+ super.setVisible(visible);
+ }
+
+ /** Saves the history when the page is disposed. */
+ public void dispose() {
+ saveInputHistory();
+ super.dispose();
+ }
+
+ /** Loads the dialog settings using the page name as a section name. */
+ private void initDialogSettings() {
+ IDialogSettings pluginSettings;
+
+ // This is strictly to get SWT Designer working locally without blowing up.
+ if( MavenPlugin.getDefault() == null ) {
+ pluginSettings = new DialogSettings("Workbench");
+ }
+ else {
+ pluginSettings = MavenPlugin.getDefault().getDialogSettings();
+ }
+
+ dialogSettings = pluginSettings.getSection(getName());
+ if(dialogSettings == null) {
+ dialogSettings = pluginSettings.addNewSection(getName());
+ pluginSettings.addSection(dialogSettings);
+ }
+ }
+
+ /** Loads the input history from the dialog settings. */
+ private void loadInputHistory() {
+ for(Map.Entry<String, List<Combo>> e : fieldsWithHistory.entrySet()) {
+ String id = e.getKey();
+ String[] items = dialogSettings.getArray(id);
+ if(items != null) {
+ for(Combo combo : e.getValue()) {
+ String text = combo.getText();
+ combo.setItems(items);
+ if(text.length() > 0) {
+ // setItems() clears the text input, so we need to restore it
+ combo.setText(text);
+ }
+ }
+ }
+ }
+ }
+
+ /** Saves the input history into the dialog settings. */
+ private void saveInputHistory() {
+ for(Map.Entry<String, List<Combo>> e : fieldsWithHistory.entrySet()) {
+ String id = e.getKey();
+
+ Set<String> history = new LinkedHashSet<String>(MAX_HISTORY);
+
+ for(Combo combo : e.getValue()) {
+ String lastValue = combo.getText();
+ if(lastValue != null && lastValue.trim().length() > 0) {
+ history.add(lastValue);
+ }
+ }
+
+ Combo combo = e.getValue().iterator().next();
+ String[] items = combo.getItems();
+ for(int j = 0; j < items.length && history.size() < MAX_HISTORY; j++ ) {
+ history.add(items[j]);
+ }
+
+ dialogSettings.put(id, history.toArray(new String[history.size()]));
+ }
+ }
+
+ /** Adds an input control to the list of fields to save. */
+ protected void addFieldWithHistory(String id, Combo combo) {
+ if(combo != null) {
+ List<Combo> combos = fieldsWithHistory.get(id);
+ if(combos == null) {
+ combos = new ArrayList<Combo>();
+ fieldsWithHistory.put(id, combos);
+ }
+ combos.add(combo);
+ }
+ }
+
+ protected String validateIdInput(String text, String id) {
+ if(text == null || text.length() == 0) {
+ return Messages.getString("wizard.project.page.maven2.validator." + id + "ID"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if(text.contains(" ")) { //$NON-NLS-1$
+ return Messages.getString("wizard.project.page.maven2.validator." + id + "IDnospaces"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ IStatus nameStatus = ResourcesPlugin.getWorkspace().validateName(text, IResource.PROJECT);
+ if(!nameStatus.isOK()) {
+ return Messages.getString("wizard.project.page.maven2.validator." + id + "IDinvalid", nameStatus.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if(!text.matches("[A-Za-z0-9_\\-.]+")) { //$NON-NLS-1$
+ return Messages.getString("wizard.project.page.maven2.validator." + id + "IDinvalid", text); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ return null;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/CustomArchetypeDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/CustomArchetypeDialog.java
new file mode 100644
index 00000000..bd919d54
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/CustomArchetypeDialog.java
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * Custom Archetype dialog
+ *
+ * @author Eugene Kuleshov
+ */
+public class CustomArchetypeDialog extends TitleAreaDialog {
+
+ private static final String DIALOG_SETTINGS = CustomArchetypeDialog.class.getName();
+
+ private static final String KEY_ARCHETYPE_GROUP_ID = "archetypeGroupId"; //$NON-NLS-1$
+
+ private static final String KEY_ARCHETYPE_ARTIFACT_ID = "archetypeArtifactId"; //$NON-NLS-1$
+
+ private static final String KEY_ARCHETYPE_VERSION = "archetypeVersion"; //$NON-NLS-1$
+
+ private static final String KEY_REPOSITORY_URL = "repositoryUrl"; //$NON-NLS-1$
+
+ private static final int MAX_HISTORY = 15;
+
+ private String title;
+
+ private String message;
+
+ private Combo archetypeGroupIdCombo;
+
+ private Combo archetypeArtifactIdCombo;
+
+ private Combo archetypeVersionCombo;
+
+ private Combo repositoryCombo;
+
+ private IDialogSettings dialogSettings;
+
+ private String archetypeArtifactId;
+
+ private String archetypeGroupId;
+
+ private String archetypeVersion;
+
+ private String repositoryUrl;
+
+ protected CustomArchetypeDialog(Shell shell, String title) {
+ super(shell);
+ this.title = title;
+ this.message = Messages.CustomArchetypeDialog_message;
+ setShellStyle(SWT.DIALOG_TRIM);
+
+ IDialogSettings pluginSettings = MavenPlugin.getDefault().getDialogSettings();
+ dialogSettings = pluginSettings.getSection(DIALOG_SETTINGS);
+ if(dialogSettings == null) {
+ dialogSettings = new DialogSettings(DIALOG_SETTINGS);
+ pluginSettings.addSection(dialogSettings);
+ }
+ }
+
+ protected Control createContents(Composite parent) {
+ Control control = super.createContents(parent);
+ setTitle(title);
+ setMessage(message);
+ return control;
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite composite1 = (Composite) super.createDialogArea(parent);
+
+ Composite composite = new Composite(composite1, SWT.NONE);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.marginTop = 7;
+ gridLayout.marginWidth = 12;
+ gridLayout.numColumns = 2;
+ composite.setLayout(gridLayout);
+
+ Label archetypeGroupIdLabel = new Label(composite, SWT.NONE);
+ archetypeGroupIdLabel.setText(Messages.CustomArchetypeDialog_lblArchetypegroupId);
+
+ archetypeGroupIdCombo = new Combo(composite, SWT.NONE);
+ GridData archetypeGroupIdComboData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+ archetypeGroupIdComboData.widthHint = 350;
+ archetypeGroupIdCombo.setLayoutData(archetypeGroupIdComboData);
+ archetypeGroupIdCombo.setItems(getSavedValues(KEY_ARCHETYPE_GROUP_ID));
+ archetypeGroupIdCombo.setData("name", "archetypeGroupId"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ Label archetypeArtifactIdLabel = new Label(composite, SWT.NONE);
+ archetypeArtifactIdLabel.setText(Messages.CustomArchetypeDialog_lblArchetypeartifactid);
+
+ archetypeArtifactIdCombo = new Combo(composite, SWT.NONE);
+ archetypeArtifactIdCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ archetypeArtifactIdCombo.setItems(getSavedValues(KEY_ARCHETYPE_ARTIFACT_ID));
+ archetypeArtifactIdCombo.setData("name", "archetypeArtifactId"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ Label archetypeVersionLabel = new Label(composite, SWT.NONE);
+ archetypeVersionLabel.setText(Messages.CustomArchetypeDialog_lblArchetypeversion);
+
+ archetypeVersionCombo = new Combo(composite, SWT.NONE);
+ archetypeVersionCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ archetypeVersionCombo.setItems(getSavedValues(KEY_ARCHETYPE_VERSION));
+ archetypeVersionCombo.setData("name", "archetypeVersion"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ Label repositoryLabel = new Label(composite, SWT.NONE);
+ repositoryLabel.setText(Messages.CustomArchetypeDialog_lblRepo);
+
+ repositoryCombo = new Combo(composite, SWT.NONE);
+ repositoryCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ repositoryCombo.setItems(getSavedValues(KEY_REPOSITORY_URL));
+ repositoryCombo.setData("name", "repository"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ ModifyListener modifyListener = new ModifyListener() {
+ public void modifyText(final ModifyEvent e) {
+ update();
+ }
+ };
+
+ archetypeGroupIdCombo.addModifyListener(modifyListener);
+ archetypeArtifactIdCombo.addModifyListener(modifyListener);
+ archetypeVersionCombo.addModifyListener(modifyListener);
+ repositoryCombo.addModifyListener(modifyListener);
+
+// fullIndexButton = new Button(composite, SWT.CHECK);
+// fullIndexButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+// fullIndexButton.setText("&Full Index");
+// fullIndexButton.setSelection(true);
+
+ return composite;
+ }
+
+ private String[] getSavedValues(String key) {
+ String[] array = dialogSettings.getArray(key);
+ return array == null ? new String[0] : array;
+ }
+
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ shell.setText(title);
+ }
+
+ public void create() {
+ super.create();
+ getButton(IDialogConstants.OK_ID).setEnabled(false);
+ }
+
+ protected void okPressed() {
+ archetypeArtifactId = archetypeArtifactIdCombo.getText().trim();
+ archetypeGroupId = archetypeGroupIdCombo.getText().trim();
+ archetypeVersion = archetypeVersionCombo.getText().trim();
+ repositoryUrl = repositoryCombo.getText().trim();
+
+ saveValue(KEY_ARCHETYPE_GROUP_ID, archetypeGroupId);
+ saveValue(KEY_ARCHETYPE_ARTIFACT_ID, archetypeArtifactId);
+ saveValue(KEY_ARCHETYPE_VERSION, archetypeVersion);
+ saveValue(KEY_REPOSITORY_URL, repositoryUrl);
+
+ super.okPressed();
+ }
+
+ public String getArchetypeGroupId() {
+ return archetypeGroupId;
+ }
+
+ public String getArchetypeArtifactId() {
+ return archetypeArtifactId;
+ }
+
+ public String getArchetypeVersion() {
+ return archetypeVersion;
+ }
+
+ public String getRepositoryUrl() {
+ return repositoryUrl;
+ }
+
+ private void saveValue(String key, String value) {
+ List<String> dirs = new ArrayList<String>();
+ dirs.addAll(Arrays.asList(getSavedValues(key)));
+
+ dirs.remove(value);
+ dirs.add(0, value);
+
+ if(dirs.size() > MAX_HISTORY) {
+ dirs = dirs.subList(0, MAX_HISTORY);
+ }
+
+ dialogSettings.put(key, dirs.toArray(new String[dirs.size()]));
+ }
+
+ void update() {
+ boolean isValid = isValid();
+ // verifyButton.setEnabled(isValid);
+ getButton(IDialogConstants.OK_ID).setEnabled(isValid);
+ }
+
+ private boolean isValid() {
+ setErrorMessage(null);
+ setMessage(null, IStatus.WARNING);
+
+ if(archetypeGroupIdCombo.getText().trim().length()==0) {
+ setErrorMessage(Messages.CustomArchetypeDialog_error_grid);
+ return false;
+ }
+
+ if(archetypeArtifactIdCombo.getText().trim().length()==0) {
+ setErrorMessage(Messages.CustomArchetypeDialog_error_artid);
+ return false;
+ }
+
+ if(archetypeVersionCombo.getText().trim().length()==0) {
+ setErrorMessage(Messages.CustomArchetypeDialog_error_version);
+ return false;
+ }
+
+ // TODO check if archetype available locally
+
+ return true;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenArtifactComponent.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenArtifactComponent.java
new file mode 100644
index 00000000..9935ca36
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenArtifactComponent.java
@@ -0,0 +1,270 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+import org.apache.maven.model.Model;
+
+import org.eclipse.m2e.core.core.Messages;
+
+
+public class MavenArtifactComponent extends Composite {
+
+ public static final String JAR = "jar"; //$NON-NLS-1$
+
+ public static final String WAR = "war"; //$NON-NLS-1$
+
+ public static final String EAR = "ear"; //$NON-NLS-1$
+
+ public static final String RAR = "rar"; //$NON-NLS-1$
+
+ public static final String POM = "pom"; //$NON-NLS-1$
+
+ // MNGECLIPSE-688 add EJB Support
+ public static final String EJB = "ejb"; //$NON-NLS-1$
+
+ public static final String[] PACKAGING_OPTIONS = {JAR, WAR, EJB, EAR, RAR, POM, //
+ "maven-plugin", "maven-archetype", "osgi-bundle", "eclipse-plugin"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+
+ public static final String DEFAULT_PACKAGING = JAR;
+
+ public static final String DEFAULT_VERSION = "0.0.1-SNAPSHOT"; //$NON-NLS-1$
+
+ /** group id text field */
+ protected Combo groupIdCombo;
+
+ /** artifact id text field */
+ protected Combo artifactIdCombo;
+
+ /** version text field */
+ protected Combo versionCombo;
+
+ /** packaging options combobox */
+ protected Combo packagingCombo;
+
+ /** name text field */
+ protected Combo nameCombo;
+
+ /** description text field */
+ protected Text descriptionText;
+
+ private ModifyListener modifyingListener;
+
+ private Label groupIdlabel;
+
+ private Label artifactIdLabel;
+
+ private Label versionLabel;
+
+ private Label packagingLabel;
+
+ private Label nameLabel;
+
+ private Label descriptionLabel;
+
+ /** Creates a new component. */
+ public MavenArtifactComponent(Composite parent, int styles) {
+ super(parent, styles);
+
+ GridLayout layout = new GridLayout();
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ layout.numColumns = 2;
+ setLayout(layout);
+
+ Group artifactGroup = new Group(this, SWT.NONE);
+ artifactGroup.setText(Messages.getString("artifactComponent.artifact")); //$NON-NLS-1$
+ GridData gd_artifactGroup = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1);
+ artifactGroup.setLayoutData(gd_artifactGroup);
+ artifactGroup.setLayout(new GridLayout(2, false));
+
+ groupIdlabel = new Label(artifactGroup, SWT.NONE);
+ groupIdlabel.setText(Messages.getString("artifactComponent.groupId")); //$NON-NLS-1$
+
+ groupIdCombo = new Combo(artifactGroup, SWT.BORDER);
+ groupIdCombo.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ groupIdCombo.setData("name", "groupIdCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ artifactIdLabel = new Label(artifactGroup, SWT.NONE);
+ artifactIdLabel.setText(Messages.getString("artifactComponent.artifactId")); //$NON-NLS-1$
+
+ artifactIdCombo = new Combo(artifactGroup, SWT.BORDER);
+ artifactIdCombo.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false));
+ artifactIdCombo.setData("name", "artifactIdCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ versionLabel = new Label(artifactGroup, SWT.NONE);
+ versionLabel.setText(Messages.getString("artifactComponent.version")); //$NON-NLS-1$
+
+ versionCombo = new Combo(artifactGroup, SWT.BORDER);
+ versionCombo.setLayoutData(new GridData(150, SWT.DEFAULT));
+ versionCombo.setText(DEFAULT_VERSION);
+ versionCombo.setData("name", "versionCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ packagingLabel = new Label(artifactGroup, SWT.NONE);
+ packagingLabel.setText(Messages.getString("artifactComponent.packaging")); //$NON-NLS-1$
+
+ packagingCombo = new Combo(artifactGroup, SWT.NONE);
+ packagingCombo.setItems(PACKAGING_OPTIONS);
+ packagingCombo.setText(DEFAULT_PACKAGING);
+ packagingCombo.setLayoutData(new GridData(150, SWT.DEFAULT));
+ packagingCombo.setData("name", "packagingCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ nameLabel = new Label(artifactGroup, SWT.NONE);
+ nameLabel.setLayoutData(new GridData());
+ nameLabel.setText(Messages.getString("artifactComponent.name")); //$NON-NLS-1$
+
+ nameCombo = new Combo(artifactGroup, SWT.BORDER);
+ nameCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ nameCombo.setData("name", "nameCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ descriptionLabel = new Label(artifactGroup, SWT.NONE);
+ descriptionLabel.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false));
+ descriptionLabel.setText(Messages.getString("artifactComponent.description")); //$NON-NLS-1$
+
+ descriptionText = new Text(artifactGroup, SWT.V_SCROLL | SWT.BORDER | SWT.WRAP);
+ GridData gd_descriptionText = new GridData(SWT.FILL, SWT.FILL, false, true);
+ gd_descriptionText.minimumHeight = 20;
+ descriptionText.setLayoutData(gd_descriptionText);
+ descriptionText.setData("name", "descriptionText"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public void setModifyingListener(ModifyListener modifyingListener) {
+ this.modifyingListener = modifyingListener;
+
+ groupIdCombo.addModifyListener(modifyingListener);
+ artifactIdCombo.addModifyListener(modifyingListener);
+ versionCombo.addModifyListener(modifyingListener);
+ packagingCombo.addModifyListener(modifyingListener);
+ }
+
+ public void dispose() {
+ super.dispose();
+
+ if(modifyingListener != null) {
+ groupIdCombo.removeModifyListener(modifyingListener);
+ artifactIdCombo.removeModifyListener(modifyingListener);
+ versionCombo.removeModifyListener(modifyingListener);
+ packagingCombo.removeModifyListener(modifyingListener);
+ }
+ }
+
+ public String getModelName() {
+ return nameCombo.getText();
+ }
+
+ public String getArtifactId() {
+ return this.artifactIdCombo.getText();
+ }
+
+ public String getGroupId() {
+ return this.groupIdCombo.getText();
+ }
+
+ public String getVersion() {
+ return this.versionCombo.getText();
+ }
+
+ public String getPackaging() {
+ return packagingCombo.getText();
+ }
+
+ public String getDescription() {
+ return descriptionText.getText();
+ }
+
+ public void setModelName(String name) {
+ nameCombo.setText(name);
+ }
+
+ public void setGroupId(String groupId) {
+ this.groupIdCombo.setText(groupId);
+ }
+
+ public void setArtifactId(String artifact) {
+ this.artifactIdCombo.setText(artifact);
+ }
+
+ public void setVersion(String version) {
+ versionCombo.setText(version);
+ }
+
+ public void setPackaging(String packaging) {
+ if(packagingCombo != null) {
+ packagingCombo.setText(packaging);
+ }
+ }
+
+ public void setDescription(String description) {
+ if(descriptionText != null) {
+ descriptionText.setText(description);
+ }
+ }
+
+ public Model getModel() {
+ Model model = new Model();
+ model.setModelVersion("4.0.0"); //$NON-NLS-1$
+
+ model.setGroupId(getGroupId());
+ model.setArtifactId(getArtifactId());
+ model.setVersion(getVersion());
+ model.setPackaging(getPackaging());
+
+ if(getModelName().length()>0) {
+ model.setName(getModelName());
+ }
+ if(getDescription().length()>0) {
+ model.setDescription(getDescription());
+ }
+
+ return model;
+ }
+
+ /** Enables or disables the artifact id text field. */
+ public void setArtifactIdEditable(boolean b) {
+ artifactIdCombo.setEnabled(b);
+ }
+
+ public Combo getGroupIdCombo() {
+ return groupIdCombo;
+ }
+
+ public Combo getArtifactIdCombo() {
+ return artifactIdCombo;
+ }
+
+ public Combo getVersionCombo() {
+ return versionCombo;
+ }
+
+ public Combo getNameCombo() {
+ return nameCombo;
+ }
+
+ public void setWidthGroup(WidthGroup widthGroup) {
+ widthGroup.addControl(this.groupIdlabel);
+ widthGroup.addControl(this.artifactIdLabel);
+ widthGroup.addControl(this.versionLabel);
+ widthGroup.addControl(this.packagingLabel);
+ widthGroup.addControl(this.nameLabel);
+ widthGroup.addControl(this.descriptionLabel);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenCheckoutLocationPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenCheckoutLocationPage.java
new file mode 100644
index 00000000..e840467e
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenCheckoutLocationPage.java
@@ -0,0 +1,424 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.wizard.IWizardContainer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+import org.apache.maven.model.Scm;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+import org.eclipse.m2e.core.scm.ScmHandlerFactory;
+import org.eclipse.m2e.core.scm.ScmHandlerUi;
+import org.eclipse.m2e.core.scm.ScmTag;
+import org.eclipse.m2e.core.scm.ScmUrl;
+
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class MavenCheckoutLocationPage extends AbstractMavenWizardPage {
+
+ String scmType;
+ ScmUrl[] scmUrls;
+ String scmParentUrl;
+
+ Combo scmTypeCombo;
+
+ Combo scmUrlCombo;
+
+ Button scmUrlBrowseButton;
+
+ Button headRevisionButton;
+
+ Label revisionLabel;
+
+ Text revisionText;
+
+ Button revisionBrowseButton;
+
+ private Button checkoutAllProjectsButton;
+
+ protected MavenCheckoutLocationPage(ProjectImportConfiguration projectImportConfiguration) {
+ super("MavenCheckoutLocationPage", projectImportConfiguration);
+ setTitle(Messages.MavenCheckoutLocationPage_title);
+ setDescription(Messages.MavenCheckoutLocationPage_description);
+ }
+
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout(5, false);
+ gridLayout.verticalSpacing = 0;
+ composite.setLayout(gridLayout);
+ setControl(composite);
+
+ SelectionAdapter selectionAdapter = new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ updatePage();
+ }
+ };
+
+ if(scmUrls == null || scmUrls.length < 2) {
+ Label urlLabel = new Label(composite, SWT.NONE);
+ urlLabel.setLayoutData(new GridData());
+ urlLabel.setText(Messages.MavenCheckoutLocationPage_lblurl);
+
+ scmTypeCombo = new Combo(composite, SWT.READ_ONLY);
+ scmTypeCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ scmTypeCombo.setData("name", "mavenCheckoutLocation.typeCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+ String[] types = ScmHandlerFactory.getTypes();
+ for(int i = 0; i < types.length; i++ ) {
+ scmTypeCombo.add(types[i]);
+ }
+ scmTypeCombo.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ String newScmType = scmTypeCombo.getText();
+ if(!newScmType.equals(scmType)) {
+ scmType = newScmType;
+ scmUrlCombo.setText(""); //$NON-NLS-1$
+ updatePage();
+ }
+ }
+ });
+
+ if(scmUrls!=null && scmUrls.length == 1) {
+ try {
+ scmType = ScmUrl.getType(scmUrls[0].getUrl());
+ } catch(CoreException ex) {
+ }
+ }
+
+ scmUrlCombo = new Combo(composite, SWT.NONE);
+ scmUrlCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ scmUrlCombo.setData("name", "mavenCheckoutLocation.urlCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ scmUrlBrowseButton = new Button(composite, SWT.NONE);
+ scmUrlBrowseButton.setLayoutData(new GridData());
+ scmUrlBrowseButton.setText(Messages.MavenCheckoutLocationPage_btnBrowse);
+ }
+
+ headRevisionButton = new Button(composite, SWT.CHECK);
+ GridData headRevisionButtonData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 5, 1);
+ headRevisionButtonData.verticalIndent = 5;
+ headRevisionButton.setLayoutData(headRevisionButtonData);
+ headRevisionButton.setText(Messages.MavenCheckoutLocationPage_btnHead);
+ headRevisionButton.setSelection(true);
+ headRevisionButton.addSelectionListener(selectionAdapter);
+
+ revisionLabel = new Label(composite, SWT.RADIO);
+ GridData revisionButtonData = new GridData();
+ revisionButtonData.horizontalIndent = 10;
+ revisionLabel.setLayoutData(revisionButtonData);
+ revisionLabel.setText(Messages.MavenCheckoutLocationPage_lblRevision);
+ // revisionButton.addSelectionListener(selectionAdapter);
+
+ revisionText = new Text(composite, SWT.BORDER);
+ GridData revisionTextData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
+ revisionTextData.widthHint = 115;
+ revisionTextData.verticalIndent = 3;
+ revisionText.setLayoutData(revisionTextData);
+
+ if(scmUrls != null) {
+ ScmTag tag = scmUrls[0].getTag();
+ if(tag!=null) {
+ headRevisionButton.setSelection(false);
+ revisionText.setText(tag.getName());
+ }
+ }
+
+ revisionText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ updatePage();
+ }
+ });
+
+ revisionBrowseButton = new Button(composite, SWT.NONE);
+ GridData gd_revisionBrowseButton = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
+ gd_revisionBrowseButton.verticalIndent = 3;
+ revisionBrowseButton.setLayoutData(gd_revisionBrowseButton);
+ revisionBrowseButton.setText(Messages.MavenCheckoutLocationPage_btnRevSelect);
+ revisionBrowseButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ String url = scmParentUrl;
+ if(url==null) {
+ return;
+ }
+
+ String scmType = scmTypeCombo.getText();
+
+ ScmHandlerUi handlerUi = ScmHandlerFactory.getHandlerUiByType(scmType);
+ String revision = handlerUi.selectRevision(getShell(), scmUrls[0], revisionText.getText());
+ if(revision!=null) {
+ revisionText.setText(revision);
+ headRevisionButton.setSelection(false);
+ updatePage();
+ }
+ }
+ });
+
+ checkoutAllProjectsButton = new Button(composite, SWT.CHECK);
+ GridData checkoutAllProjectsData = new GridData(SWT.LEFT, SWT.TOP, true, false, 5, 1);
+ checkoutAllProjectsData.verticalIndent = 10;
+ checkoutAllProjectsButton.setLayoutData(checkoutAllProjectsData);
+ checkoutAllProjectsButton.setText(Messages.MavenCheckoutLocationPage_btnCheckout);
+ checkoutAllProjectsButton.setSelection(true);
+ checkoutAllProjectsButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ updatePage();
+ }
+ });
+
+ GridData advancedSettingsData = new GridData(SWT.FILL, SWT.TOP, true, false, 5, 1);
+ advancedSettingsData.verticalIndent = 10;
+ createAdvancedSettings(composite, advancedSettingsData);
+
+ if(scmUrls!=null && scmUrls.length == 1) {
+ scmTypeCombo.setText(scmType == null ? "" : scmType); //$NON-NLS-1$
+ scmUrlCombo.setText(scmUrls[0].getProviderUrl());
+ }
+
+ if(scmUrls == null || scmUrls.length < 2) {
+ scmUrlBrowseButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ ScmHandlerUi handlerUi = ScmHandlerFactory.getHandlerUiByType(scmType);
+ // XXX should use null if there is no scmUrl selected
+ ScmUrl currentUrl = scmUrls==null || scmUrls.length==0 ? new ScmUrl("scm:" + scmType + ":") : scmUrls[0]; //$NON-NLS-1$ //$NON-NLS-2$
+ ScmUrl scmUrl = handlerUi.selectUrl(getShell(), currentUrl);
+ if(scmUrl!=null) {
+ scmUrlCombo.setText(scmUrl.getProviderUrl());
+ if(scmUrls==null) {
+ scmUrls = new ScmUrl[1];
+ }
+ scmUrls[0] = scmUrl;
+ scmParentUrl = scmUrl.getUrl();
+ updatePage();
+ }
+ }
+ });
+
+ scmUrlCombo.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ final String url = scmUrlCombo.getText();
+ if(url.startsWith("scm:")) { //$NON-NLS-1$
+ try {
+ final String type = ScmUrl.getType(url);
+ scmTypeCombo.setText(type);
+ scmType = type;
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ scmUrlCombo.setText(url.substring(type.length() + 5));
+ }
+ });
+ } catch(CoreException ex) {
+ }
+ return;
+ }
+
+ if(scmUrls==null) {
+ scmUrls = new ScmUrl[1];
+ }
+
+ ScmUrl scmUrl = new ScmUrl("scm:" + scmType + ":" + url); //$NON-NLS-1$ //$NON-NLS-2$
+ scmUrls[0] = scmUrl;
+ scmParentUrl = scmUrl.getUrl();
+ updatePage();
+ }
+ });
+ }
+
+ updatePage();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.wizards.AbstractMavenWizardPage#setVisible(boolean)
+ */
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+
+ if(dialogSettings!=null && scmUrlCombo!=null) {
+ String[] items = dialogSettings.getArray("scmUrl"); //$NON-NLS-1$
+ if(items != null) {
+ String text = scmUrlCombo.getText();
+ scmUrlCombo.setItems(items);
+ if (text.length() > 0) {
+ // setItems() clears the text input, so we need to restore it
+ scmUrlCombo.setText(text);
+ }
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.wizards.AbstractMavenWizardPage#dispose()
+ */
+ public void dispose() {
+ if(dialogSettings != null && scmUrlCombo!=null) {
+ Set<String> history = new LinkedHashSet<String>(MAX_HISTORY);
+
+ String lastValue = scmUrlCombo.getText();
+ if ( lastValue!=null && lastValue.trim().length() > 0 ) {
+ history.add("scm:" + scmType + ":" + lastValue); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ String[] items = scmUrlCombo.getItems();
+ for(int j = 0; j < items.length && history.size() < MAX_HISTORY; j++ ) {
+ history.add(items[j]);
+ }
+
+ dialogSettings.put("scmUrl", history.toArray(new String[history.size()])); //$NON-NLS-1$
+ }
+
+ super.dispose();
+ }
+
+ public IWizardContainer getContainer() {
+ return super.getContainer();
+ }
+
+ void updatePage() {
+ boolean canSelectUrl = false ;
+ boolean canSelectRevision = false;
+ ScmHandlerUi handlerUi = ScmHandlerFactory.getHandlerUiByType(scmType);
+ if(handlerUi!=null) {
+ canSelectUrl = handlerUi.canSelectUrl();
+ canSelectRevision = handlerUi.canSelectRevision();
+ }
+
+ if(scmUrlBrowseButton!=null) {
+ scmUrlBrowseButton.setEnabled(canSelectUrl);
+ }
+
+ revisionBrowseButton.setEnabled(canSelectRevision);
+
+ boolean isHeadRevision = isHeadRevision();
+ revisionLabel.setEnabled(!isHeadRevision);
+ revisionText.setEnabled(!isHeadRevision);
+
+ setPageComplete(isPageValid());
+ }
+
+ private boolean isPageValid() {
+ setErrorMessage(null);
+
+ if(scmUrls != null && scmUrls.length < 2) {
+ if(scmType == null) {
+ setErrorMessage(Messages.MavenCheckoutLocationPage_error_empty);
+ return false;
+ }
+ }
+
+ ScmHandlerUi handlerUi = ScmHandlerFactory.getHandlerUiByType(scmType);
+
+ if(scmUrls == null || scmUrls.length < 2) {
+ if(scmUrls == null || scmUrls.length == 0) {
+ setErrorMessage(Messages.MavenCheckoutLocationPage_error_empty_url);
+ return false;
+ }
+
+ if(handlerUi!=null && !handlerUi.isValidUrl(scmUrls[0].getUrl())) {
+ setErrorMessage(Messages.MavenCheckoutLocationPage_error_url_empty);
+ return false;
+ }
+ }
+
+ if(!isHeadRevision()) {
+ String revision = revisionText.getText().trim();
+ if(revision.length()==0) {
+ setErrorMessage(Messages.MavenCheckoutLocationPage_error_scm_empty);
+ return false;
+ }
+
+ if(handlerUi!=null && !handlerUi.isValidRevision(null, revision)) {
+ setErrorMessage(Messages.MavenCheckoutLocationPage_error_scm_invalid);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void setParent(String parentUrl) {
+ this.scmParentUrl = parentUrl;
+ }
+
+ public void setUrls(ScmUrl[] urls) {
+ this.scmUrls = urls;
+ }
+
+ public ScmUrl[] getUrls() {
+ return scmUrls;
+ }
+
+ public Scm[] getScms() {
+ if(scmUrls==null) {
+ return new Scm[0];
+ }
+
+ String revision = getRevision();
+ Scm[] scms = new Scm[scmUrls.length];
+ for(int i = 0; i < scms.length; i++ ) {
+ Scm scm = new Scm();
+ scm.setConnection(scmUrls[i].getUrl());
+ scm.setTag(revision);
+ scms[i] = scm;
+ }
+ return scms;
+ }
+
+ public boolean isCheckoutAllProjects() {
+ return checkoutAllProjectsButton.getSelection();
+ }
+
+ public boolean isHeadRevision() {
+ return headRevisionButton.getSelection();
+ }
+
+ public String getRevision() {
+ if(isHeadRevision()) {
+ return "HEAD"; //$NON-NLS-1$
+ }
+ return revisionText.getText().trim();
+ }
+
+ public void addListener(final SelectionListener listener) {
+ ModifyListener listenerProxy = new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ Event event = new Event();
+ event.widget = e.widget;
+ listener.widgetSelected(new SelectionEvent(event));
+ }
+ };
+ scmUrlCombo.addModifyListener(listenerProxy);
+ revisionText.addModifyListener(listenerProxy);
+ headRevisionButton.addSelectionListener(listener);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenCheckoutWizard.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenCheckoutWizard.java
new file mode 100644
index 00000000..53f3b54a
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenCheckoutWizard.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.IAdapterManager;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IImportWizard;
+import org.eclipse.ui.INewWizard;
+import org.eclipse.ui.IWorkbench;
+
+import org.apache.maven.model.Scm;
+
+import org.eclipse.m2e.core.actions.SelectionUtil;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.MavenProjectScmInfo;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+import org.eclipse.m2e.core.scm.ScmUrl;
+
+
+/**
+ * Maven checkout wizard
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenCheckoutWizard extends Wizard implements IImportWizard, INewWizard {
+
+ private final ProjectImportConfiguration importConfiguration = new ProjectImportConfiguration();
+
+ private ScmUrl[] urls;
+
+ private String parentUrl;
+
+ private MavenCheckoutLocationPage scheckoutPage;
+
+ private MavenProjectWizardLocationPage locationPage;
+
+ private IStructuredSelection selection;
+
+
+ public MavenCheckoutWizard() {
+ this(null);
+ setNeedsProgressMonitor(true);
+ }
+
+ public MavenCheckoutWizard(ScmUrl[] urls) {
+ setUrls(urls);
+ setNeedsProgressMonitor(true);
+ setWindowTitle(Messages.MavenCheckoutWizard_title);
+ }
+
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ this.selection = selection;
+
+ importConfiguration.setWorkingSet(SelectionUtil.getSelectedWorkingSet(selection));
+
+ ArrayList<ScmUrl> urls = new ArrayList<ScmUrl>();
+ IAdapterManager adapterManager = Platform.getAdapterManager();
+ for(Iterator<?> it = selection.iterator(); it.hasNext();) {
+ ScmUrl url = (ScmUrl) adapterManager.getAdapter(it.next(), ScmUrl.class);
+ if(url!=null) {
+ urls.add(url);
+ }
+ }
+ setUrls(urls.toArray(new ScmUrl[urls.size()]));
+ }
+
+ private void setUrls(ScmUrl[] urls) {
+ if(urls!=null && urls.length>0) {
+ this.urls = urls;
+ this.parentUrl = getParentUrl(urls);
+ }
+ }
+
+ private String getParentUrl(ScmUrl[] urls) {
+ if(urls.length==1) {
+ return urls[0].getUrl();
+ }
+
+ String parent = urls[0].getParentUrl();
+ for(int i = 1; parent!=null && i < urls.length; i++ ) {
+ String url = urls[i].getParentUrl();
+ if(!parent.equals(url)) {
+ parent = null;
+ }
+ }
+ return parent;
+ }
+
+ public void addPages() {
+ scheckoutPage = new MavenCheckoutLocationPage(importConfiguration);
+ scheckoutPage.setUrls(urls);
+ scheckoutPage.setParent(parentUrl);
+
+ locationPage = new MavenProjectWizardLocationPage(importConfiguration, //
+ Messages.MavenCheckoutWizard_location1,
+ Messages.MavenCheckoutWizard_location2);
+ locationPage.setLocationPath(SelectionUtil.getSelectedLocation(selection));
+
+ addPage(scheckoutPage);
+ addPage(locationPage);
+ }
+
+// /** Adds the listeners after the page controls are created. */
+// public void createPageControls(Composite pageContainer) {
+// super.createPageControls(pageContainer);
+//
+// locationPage.addListener(new SelectionAdapter() {
+// public void widgetSelected(SelectionEvent e) {
+// projectsPage.setScms(locationPage.getScms(new NullProgressMonitor()));
+// }
+// });
+//
+// projectsPage.setScms(locationPage.getScms(new NullProgressMonitor()));
+// }
+
+ public boolean canFinish() {
+ if(scheckoutPage.isCheckoutAllProjects() && scheckoutPage.isPageComplete()) {
+ return true;
+ }
+ return super.canFinish();
+ }
+
+ public boolean performFinish() {
+ if(!canFinish()) {
+ return false;
+ }
+
+ final boolean checkoutAllProjects = scheckoutPage.isCheckoutAllProjects();
+
+ Scm[] scms = scheckoutPage.getScms();
+
+ final Collection<MavenProjectScmInfo> mavenProjects = new ArrayList<MavenProjectScmInfo>();
+ for(int i = 0; i < scms.length; i++ ) {
+ String url = scms[i].getConnection();
+ String revision = scms[i].getTag();
+
+ if(url.endsWith("/")) { //$NON-NLS-1$
+ url = url.substring(0, url.length()-1);
+ }
+
+ int n = url.lastIndexOf("/"); //$NON-NLS-1$
+ String label = (n == -1 ? url : url.substring(n)) + "/" + IMavenConstants.POM_FILE_NAME; //$NON-NLS-1$
+ MavenProjectScmInfo projectInfo = new MavenProjectScmInfo(label, null, //
+ null, revision, url, url);
+ mavenProjects.add(projectInfo);
+ }
+
+ MavenProjectCheckoutJob job = new MavenProjectCheckoutJob(importConfiguration, checkoutAllProjects) {
+ protected Collection<MavenProjectScmInfo> getProjects(IProgressMonitor monitor) {
+ return mavenProjects;
+ }
+ };
+
+ if(!locationPage.isInWorkspace()) {
+ job.setLocation(locationPage.getLocationPath().toFile());
+ }
+
+ job.schedule();
+
+ return true;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenDependenciesWizardPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenDependenciesWizardPage.java
new file mode 100644
index 00000000..4e66a4d4
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenDependenciesWizardPage.java
@@ -0,0 +1,291 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.IWizardContainer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+import org.apache.maven.model.Dependency;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+import org.eclipse.m2e.core.ui.dialogs.MavenRepositorySearchDialog;
+
+
+/**
+ * Wizard page for gathering information about Maven artifacts. Allows to select
+ * artifacts from the repository index.
+ */
+public class MavenDependenciesWizardPage extends AbstractMavenWizardPage {
+
+ /**
+ * Viewer containing dependencies
+ */
+ TableViewer dependencyViewer;
+
+ private Dependency[] dependencies;
+
+ /**
+ * Listeners notified about all changes
+ */
+ private List<ISelectionChangedListener> listeners = new ArrayList<ISelectionChangedListener>();
+
+ boolean showScope = false;
+
+ public MavenDependenciesWizardPage() {
+ this(null, Messages.getString("wizard.project.page.dependencies.title"), // //$NON-NLS-1$
+ Messages.getString("wizard.project.page.dependencies.description")); //$NON-NLS-1$
+ }
+
+ public MavenDependenciesWizardPage(ProjectImportConfiguration projectImportConfiguration, String title, String description) {
+ super("MavenDependenciesWizardPage", projectImportConfiguration); //$NON-NLS-1$
+ setTitle(title);
+ setDescription(description);
+ setPageComplete(true);
+ }
+
+ public void setShowScope(boolean showScope) {
+ this.showScope = showScope;
+ }
+
+ public void setDependencies(Dependency[] dependencies) {
+ this.dependencies = dependencies;
+ }
+
+ /**
+ * {@inheritDoc} This wizard page contains a <code>TableViewer</code> to display the currently included Maven2
+ * directories and a button area with buttons to add further dependencies or remove existing ones.
+ */
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NULL);
+ GridLayout layout = new GridLayout(3, false);
+ composite.setLayout(layout);
+
+ if(dependencies!=null) {
+ createArtifacts(composite);
+ }
+
+ createAdvancedSettings(composite, new GridData(SWT.FILL, SWT.TOP, false, false, 3, 1));
+
+ setControl(composite);
+
+ updatePage();
+ }
+
+ private void createArtifacts(Composite composite) {
+ Label mavenArtifactsLabel = new Label(composite, SWT.NONE);
+ mavenArtifactsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+ mavenArtifactsLabel.setText(org.eclipse.m2e.core.internal.Messages.MavenDependenciesWizardPage_lblArtifacts);
+
+ dependencyViewer = new TableViewer(composite, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
+ dependencyViewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 2));
+ dependencyViewer.setUseHashlookup(true);
+ dependencyViewer.setLabelProvider(new ArtifactLabelProvider());
+ dependencyViewer.setComparator(new DependencySorter());
+ dependencyViewer.add(dependencies);
+
+ Button addDependencyButton = new Button(composite, SWT.PUSH);
+ GridData gd_addDependencyButton = new GridData(SWT.FILL, SWT.TOP, false, false);
+ addDependencyButton.setLayoutData(gd_addDependencyButton);
+ addDependencyButton.setText(Messages.getString("wizard.project.page.dependencies.add")); //$NON-NLS-1$
+
+ addDependencyButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ MavenRepositorySearchDialog dialog = new MavenRepositorySearchDialog(getShell(), //
+ org.eclipse.m2e.core.internal.Messages.MavenDependenciesWizardPage_searchDialog_title, IIndex.SEARCH_ARTIFACT, Collections.<ArtifactKey>emptySet(), showScope);
+ if(dialog.open() == Window.OK) {
+ Object result = dialog.getFirstResult();
+ if(result instanceof IndexedArtifactFile) {
+ Dependency dependency = ((IndexedArtifactFile) result).getDependency();
+ dependency.setScope(dialog.getSelectedScope());
+ dependencyViewer.add(dependency);
+ notifyListeners();
+ } else if(result instanceof IndexedArtifact) {
+ // If we have an ArtifactInfo, we add the first FileInfo it contains
+ // which corresponds to the latest version of the artifact.
+ Set<IndexedArtifactFile> files = ((IndexedArtifact) result).getFiles();
+ if(files != null && !files.isEmpty()) {
+ dependencyViewer.add(files.iterator().next().getDependency());
+ notifyListeners();
+ }
+ }
+ }
+ }
+ });
+
+ final Button removeDependencyButton = new Button(composite, SWT.PUSH);
+ removeDependencyButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, true));
+ removeDependencyButton.setText(Messages.getString("wizard.project.page.dependencies.remove")); //$NON-NLS-1$
+ removeDependencyButton.setEnabled(false);
+
+ removeDependencyButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ IStructuredSelection selection = (IStructuredSelection) dependencyViewer.getSelection();
+ if(selection != null) {
+ dependencyViewer.remove(selection.toArray());
+ notifyListeners();
+ }
+ }
+ });
+
+ dependencyViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+ removeDependencyButton.setEnabled(selection.size() > 0);
+ }
+ });
+ }
+
+ public IWizardContainer getContainer() {
+ return super.getContainer();
+ }
+
+ void updatePage() {
+ setPageComplete(isPageValid());
+ }
+
+ private boolean isPageValid() {
+ setErrorMessage(null);
+ return true;
+ }
+
+ /**
+ * Notify listeners about changes
+ */
+ protected void notifyListeners() {
+ SelectionChangedEvent event = new SelectionChangedEvent(dependencyViewer, dependencyViewer.getSelection());
+ for(ISelectionChangedListener listener : listeners) {
+ listener.selectionChanged(event);
+ }
+ }
+
+ public void addListener(ISelectionChangedListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Returns dependencies currently chosen by the user.
+ *
+ * @return dependencies currently chosen by the user. Neither the array nor any of its elements is
+ * <code>null</code>.
+ */
+ public Dependency[] getDependencies() {
+ List<Dependency> dependencies = new ArrayList<Dependency>();
+ for(int i = 0; i < dependencyViewer.getTable().getItemCount(); i++ ) {
+ Object element = dependencyViewer.getElementAt(i);
+ if(element instanceof Dependency) {
+ dependencies.add((Dependency) element);
+ }
+ }
+ return dependencies.toArray(new Dependency[dependencies.size()]);
+ }
+
+
+ /**
+ * Simple <code>LabelProvider</code> attached to the dependency viewer.
+ * <p>
+ * The information displayed for objects of type <code>Dependency</code> inside the dependency viewer is the
+ * following:
+ * </p>
+ * <p>
+ * {groupId} - {artifactId} - {version} - {type}
+ * </p>
+ */
+ public static class ArtifactLabelProvider extends LabelProvider {
+
+ /** The image to show for all objects of type <code>Dependency</code>. */
+ private static final Image DEPENDENCY_IMAGE = MavenImages.IMG_JAR;
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The text returned for objects of type <code>Dependency</code> contains the following information about the
+ * dependency:
+ * </p>
+ * <p>
+ * {groupId} - {artifactId} - {version} - {type}
+ * </p>
+ */
+ public String getText(Object element) {
+ if(element instanceof Dependency) {
+ Dependency d = (Dependency) element;
+ return d.getGroupId() + ":" + d.getArtifactId() + ":" + d.getVersion() + (d.getClassifier() == null ? "" : ":" + d.getClassifier()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+ return super.getText(element);
+ }
+
+ public Image getImage(Object element) {
+ if(element instanceof Dependency) {
+ return DEPENDENCY_IMAGE;
+ }
+ return super.getImage(element);
+ }
+ }
+
+ /**
+ * Simple <code>ViewerComparator</code> attached to the dependency viewer. Objects of type <code>Dependency</code> are
+ * sorted by (1) their groupId and (2) their artifactId.
+ */
+ public static class DependencySorter extends ViewerComparator {
+
+ /**
+ * Two objects of type <code>Dependency</code> are sorted by (1) their groupId and (2) their artifactId.
+ */
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ if(!(e1 instanceof Dependency) || !(e2 instanceof Dependency)) {
+ return super.compare(viewer, e1, e2);
+ }
+
+ // First of all, compare the group IDs of the two dependencies.
+ String group1 = ((Dependency) e1).getGroupId();
+ String group2 = ((Dependency) e2).getGroupId();
+
+ int result = (group1 == null) ? -1 : group1.compareToIgnoreCase(group2);
+
+ // If the group IDs match, we sort by the artifact IDs.
+ if(result == 0) {
+ String artifact1 = ((Dependency) e1).getArtifactId();
+ String artifact2 = ((Dependency) e2).getArtifactId();
+ result = artifact1 == null ? -1 : artifact1.compareToIgnoreCase(artifact2);
+ }
+
+ return result;
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenImportWizard.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenImportWizard.java
new file mode 100644
index 00000000..3eeafc8b
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenImportWizard.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.resources.WorkspaceJob;
+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.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IImportWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.progress.IProgressConstants;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.actions.OpenMavenConsoleAction;
+import org.eclipse.m2e.core.actions.SelectionUtil;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.MavenProjectInfo;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+
+
+/**
+ * Maven Import Wizard
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenImportWizard extends Wizard implements IImportWizard {
+
+ final ProjectImportConfiguration importConfiguration;
+
+ private MavenImportWizardPage page;
+
+ private List<String> locations;
+
+ private boolean showLocation = true;
+
+ public MavenImportWizard() {
+ importConfiguration = new ProjectImportConfiguration();
+ setNeedsProgressMonitor(true);
+ setWindowTitle(Messages.MavenImportWizard_title);
+ }
+
+ public MavenImportWizard(ProjectImportConfiguration importConfiguration, List<String> locations) {
+ this.importConfiguration = importConfiguration;
+ this.locations = locations;
+ this.showLocation = false;
+ setNeedsProgressMonitor(true);
+ }
+
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ if(locations == null || locations.isEmpty()) {
+ IPath location = SelectionUtil.getSelectedLocation(selection);
+ if(location != null) {
+ locations = Collections.singletonList(location.toOSString());
+ }
+ }
+
+ importConfiguration.setWorkingSet(SelectionUtil.getSelectedWorkingSet(selection));
+ }
+
+ public void addPages() {
+ page = new MavenImportWizardPage(importConfiguration);
+ page.setLocations(locations);
+ page.setShowLocation(showLocation);
+ addPage(page);
+ }
+
+ public boolean performFinish() {
+ if(!page.isPageComplete()) {
+ return false;
+ }
+
+ final Collection<MavenProjectInfo> projects = page.getProjects();
+
+ final MavenPlugin plugin = MavenPlugin.getDefault();
+
+ Job job = new WorkspaceJob(Messages.MavenImportWizard_job) {
+ public IStatus runInWorkspace(IProgressMonitor monitor) {
+ setProperty(IProgressConstants.ACTION_PROPERTY, new OpenMavenConsoleAction());
+ try {
+ plugin.getProjectConfigurationManager().importProjects(projects, importConfiguration, monitor);
+ } catch(CoreException ex) {
+ plugin.getConsole().logError("Projects imported with errors");
+ return ex.getStatus();
+ }
+
+ return Status.OK_STATUS;
+ }
+ };
+ job.setRule(plugin.getProjectConfigurationManager().getRule());
+ job.schedule();
+
+ return true;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenImportWizardPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenImportWizardPage.java
new file mode 100644
index 00000000..f838854f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenImportWizardPage.java
@@ -0,0 +1,525 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Tree;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Parent;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.embedder.MavenModelManager;
+import org.eclipse.m2e.core.project.AbstractProjectScanner;
+import org.eclipse.m2e.core.project.LocalProjectScanner;
+import org.eclipse.m2e.core.project.MavenProjectInfo;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+
+
+/**
+ * Maven Import Wizard Page
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenImportWizardPage extends AbstractMavenWizardPage {
+
+ static final Object[] EMPTY = new Object[0];
+
+ protected Combo rootDirectoryCombo;
+
+ protected CheckboxTreeViewer projectTreeViewer;
+
+ private List<String> locations;
+
+ private IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+
+ private WorkingSetGroup workingSetGroup;
+
+ private boolean showLocation = true;
+
+ protected MavenImportWizardPage(ProjectImportConfiguration importConfiguration) {
+ super("MavenProjectImportWizardPage", importConfiguration);
+ setTitle(org.eclipse.m2e.core.internal.Messages.MavenImportWizardPage_title);
+ setDescription(org.eclipse.m2e.core.internal.Messages.MavenImportWizardPage_desc);
+ setPageComplete(false);
+ }
+
+ public void setShowLocation(boolean showLocation) {
+ this.showLocation = showLocation;
+ }
+
+ public void setLocations(List<String> locations) {
+ this.locations = locations;
+ }
+
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(3, false));
+ setControl(composite);
+
+ if(showLocation || locations==null || locations.isEmpty()) {
+ final Label selectRootDirectoryLabel = new Label(composite, SWT.NONE);
+ selectRootDirectoryLabel.setLayoutData(new GridData());
+ selectRootDirectoryLabel.setText(Messages.getString("wizard.import.page.root")); //$NON-NLS-1$
+
+ rootDirectoryCombo = new Combo(composite, SWT.NONE);
+ rootDirectoryCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ rootDirectoryCombo.addSelectionListener(new SelectionAdapter() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ if(rootDirectoryCombo.getText().trim().length() > 0) {
+ scanProjects();
+ }
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ if(rootDirectoryCombo.getText().trim().length() > 0) {
+ scanProjects();
+ }
+ }
+ });
+ rootDirectoryCombo.setFocus();
+ addFieldWithHistory("rootDirectory", rootDirectoryCombo); //$NON-NLS-1$
+
+ if(locations!=null && locations.size()==1) {
+ rootDirectoryCombo.setText(locations.get(0));
+ }
+
+ final Button browseButton = new Button(composite, SWT.NONE);
+ browseButton.setText(Messages.getString("wizard.import.page.browse")); //$NON-NLS-1$
+ browseButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ browseButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ DirectoryDialog dialog = new DirectoryDialog(getShell(), SWT.NONE);
+ dialog.setText(Messages.getString("wizard.import.page.selectRootFolder")); //$NON-NLS-1$
+ String path = rootDirectoryCombo.getText();
+ if(path.length()==0) {
+ path = ResourcesPlugin.getWorkspace().getRoot().getLocation().toPortableString();
+ }
+ dialog.setFilterPath(path);
+
+ String result = dialog.open();
+ if(result != null) {
+ rootDirectoryCombo.setText(result);
+ scanProjects();
+ }
+ }
+ });
+ }
+
+ final Label projectsLabel = new Label(composite, SWT.NONE);
+ projectsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+ projectsLabel.setText(Messages.getString("wizard.import.page.projects")); //$NON-NLS-1$
+
+ projectTreeViewer = new CheckboxTreeViewer(composite, SWT.BORDER);
+
+ projectTreeViewer.addCheckStateListener(new ICheckStateListener() {
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ projectTreeViewer.setSubtreeChecked(event.getElement(), event.getChecked());
+ updateCheckedState();
+ Object[] checkedElements = projectTreeViewer.getCheckedElements();
+ setPageComplete(checkedElements != null && checkedElements.length > 0);
+ }
+ });
+
+ projectTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+ validateProjectInfo((MavenProjectInfo) selection.getFirstElement());
+ }});
+
+ projectTreeViewer.setContentProvider(new ITreeContentProvider() {
+
+ public Object[] getElements(Object element) {
+ if(element instanceof List) {
+ @SuppressWarnings("unchecked")
+ List<MavenProjectInfo> projects = (List<MavenProjectInfo>) element;
+ return projects.toArray(new MavenProjectInfo[projects.size()]);
+ }
+ return EMPTY;
+ }
+
+ public Object[] getChildren(Object parentElement) {
+ if(parentElement instanceof List) {
+ @SuppressWarnings("unchecked")
+ List<MavenProjectInfo> projects = (List<MavenProjectInfo>) parentElement;
+ return projects.toArray(new MavenProjectInfo[projects.size()]);
+ } else if(parentElement instanceof MavenProjectInfo) {
+ MavenProjectInfo mavenProjectInfo = (MavenProjectInfo) parentElement;
+ Collection<MavenProjectInfo> projects = mavenProjectInfo.getProjects();
+ return projects.toArray(new MavenProjectInfo[projects.size()]);
+ }
+ return EMPTY;
+ }
+
+ public Object getParent(Object element) {
+ return null;
+ }
+
+ public boolean hasChildren(Object parentElement) {
+ if(parentElement instanceof List) {
+ List<?> projects = (List<?>) parentElement;
+ return !projects.isEmpty();
+ } else if(parentElement instanceof MavenProjectInfo) {
+ MavenProjectInfo mavenProjectInfo = (MavenProjectInfo) parentElement;
+ return !mavenProjectInfo.getProjects().isEmpty();
+ }
+ return false;
+ }
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+ });
+
+ projectTreeViewer.setLabelProvider(new ProjectLabelProvider());
+
+ final Tree projectTree = projectTreeViewer.getTree();
+ GridData projectTreeData = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 3);
+ projectTreeData.heightHint = 250;
+ projectTreeData.widthHint = 500;
+ projectTree.setLayoutData(projectTreeData);
+
+ final Button selectAllButton = new Button(composite, SWT.NONE);
+ selectAllButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ selectAllButton.setText(Messages.getString("wizard.import.page.selectAll")); //$NON-NLS-1$
+ selectAllButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ projectTreeViewer.expandAll();
+ setAllChecked(true);
+ // projectTreeViewer.setSubtreeChecked(projectTreeViewer.getInput(), true);
+ validate();
+ }
+ });
+
+ final Button deselectAllButton = new Button(composite, SWT.NONE);
+ deselectAllButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ deselectAllButton.setText(Messages.getString("wizard.import.page.deselectAll")); //$NON-NLS-1$
+ deselectAllButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ setAllChecked(false);
+ // projectTreeViewer.setSubtreeChecked(projectTreeViewer.getInput(), false);
+ setPageComplete(false);
+ }
+ });
+
+ final Button refreshButton = new Button(composite, SWT.NONE);
+ refreshButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, true));
+ refreshButton.setText(Messages.getString("wizard.import.page.refresh")); //$NON-NLS-1$
+ refreshButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ scanProjects();
+ }
+ });
+
+ this.workingSetGroup = new WorkingSetGroup(composite, getImportConfiguration(), getShell());
+
+ createAdvancedSettings(composite, new GridData(SWT.FILL, SWT.TOP, false, false, 3, 1));
+ resolverConfigurationComponent.template.addModifyListener(new ModifyListener(){
+ public void modifyText(ModifyEvent arg0) {
+ validate();
+ }
+ });
+
+ if(locations!=null && !locations.isEmpty()) {
+ scanProjects();
+ }
+ }
+
+ public void dispose() {
+ super.dispose();
+ workingSetGroup.dispose();
+ }
+
+ protected void scanProjects() {
+ final AbstractProjectScanner<MavenProjectInfo> projectScanner = getProjectScanner();
+ try {
+ getWizard().getContainer().run(true, true, new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ projectScanner.run(monitor);
+ }
+ });
+
+ projectTreeViewer.setInput(projectScanner.getProjects());
+ projectTreeViewer.expandAll();
+ // projectTreeViewer.setAllChecked(true);
+ setAllChecked(true);
+ Object[] checkedElements = projectTreeViewer.getCheckedElements();
+ setPageComplete(checkedElements != null && checkedElements.length > 0);
+ setErrorMessage(null);
+ setMessage(null);
+
+ List<Throwable> errors = projectScanner.getErrors();
+ if(!errors.isEmpty()) {
+ StringBuffer sb = new StringBuffer(Messages.getString("wizard.import.page.scanningErrors", errors.size())); //$NON-NLS-1$
+ int n = 1;
+ for(Throwable ex : errors) {
+ if(ex instanceof CoreException) {
+ String msg = ((CoreException) ex).getStatus().getMessage();
+ sb.append("\n ").append(n).append(" ").append(msg.trim()); //$NON-NLS-1$ //$NON-NLS-2$
+
+ } else {
+ String msg = ex.getMessage()==null ? ex.toString() : ex.getMessage();
+ sb.append("\n ").append(n).append(" ").append(msg.trim()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ n++;
+ }
+
+ setMessage(sb.toString(), IMessageProvider.WARNING);
+ }
+
+ } catch(InterruptedException ex) {
+ // canceled
+
+ } catch(InvocationTargetException ex) {
+ Throwable e = ex.getTargetException() == null ? ex : ex.getTargetException();
+ String msg;
+ if(e instanceof CoreException) {
+ msg = e.getMessage();
+ MavenLogger.log(msg, e);
+ } else {
+ msg = "Scanning error " + projectScanner.getDescription() + "; " + e.toString(); //$NON-NLS-2$
+ MavenPlugin.getDefault().getConsole().logError(msg);
+ MavenLogger.log(msg, e);
+ }
+ projectTreeViewer.setInput(null);
+ setPageComplete(false);
+ setErrorMessage(msg);
+
+ }
+ }
+
+ void setAllChecked(boolean state) {
+ @SuppressWarnings("unchecked")
+ List<MavenProjectInfo> input = (List<MavenProjectInfo>) projectTreeViewer.getInput();
+ if(input!=null) {
+ for(MavenProjectInfo mavenProjectInfo : input) {
+ projectTreeViewer.setSubtreeChecked(mavenProjectInfo, state);
+ }
+ updateCheckedState();
+ }
+ }
+
+ void updateCheckedState() {
+ Object[] elements = projectTreeViewer.getCheckedElements();
+ for(int i = 0; i < elements.length; i++ ) {
+ Object element = elements[i];
+ if(element instanceof MavenProjectInfo) {
+ MavenProjectInfo info = (MavenProjectInfo) element;
+ if(isWorkspaceFolder(info) || isAlreadyExists(info)) {
+ projectTreeViewer.setChecked(info, false);
+ }
+ }
+ }
+ }
+
+ boolean isWorkspaceFolder(MavenProjectInfo info) {
+ if(info!=null) {
+ File pomFile = info.getPomFile();
+ if(pomFile != null) {
+ File parentFile = pomFile.getParentFile();
+ if(parentFile.getAbsolutePath().equals(workspaceRoot.getLocation().toFile().getAbsolutePath())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ boolean isAlreadyExists(MavenProjectInfo info) {
+ if(info!=null) {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IProject project = getImportConfiguration().getProject(workspace.getRoot(), info.getModel());
+ return project.exists();
+ }
+ return false;
+ }
+
+ protected AbstractProjectScanner<MavenProjectInfo> getProjectScanner() {
+ File root = workspaceRoot.getLocation().toFile();
+ MavenPlugin mavenPlugin = MavenPlugin.getDefault();
+ MavenModelManager modelManager = mavenPlugin.getMavenModelManager();
+ MavenConsole console = mavenPlugin.getConsole();
+ if(showLocation || locations == null || locations.isEmpty()) {
+ return new LocalProjectScanner(root, rootDirectoryCombo.getText(), false, modelManager, console);
+ }
+ return new LocalProjectScanner(root, locations, true, modelManager, console);
+ }
+
+ /**
+ * @return collection of <code>MavenProjectInfo</code>
+ */
+ public Collection<MavenProjectInfo> getProjects() {
+ Collection<MavenProjectInfo> checkedProjects = new ArrayList<MavenProjectInfo>();
+ for(Object o : projectTreeViewer.getCheckedElements()) {
+ checkedProjects.add((MavenProjectInfo) o);
+ }
+
+ return checkedProjects;
+ }
+
+ private void collectProjects(List<MavenProjectInfo> mavenProjects, Set<MavenProjectInfo> checkedProjects,
+ Collection<MavenProjectInfo> childProjects) {
+ for(MavenProjectInfo projectInfo : childProjects) {
+ if(checkedProjects.contains(projectInfo)) {
+ mavenProjects.add(projectInfo);
+ } else {
+ collectProjects(mavenProjects, checkedProjects, projectInfo.getProjects());
+ }
+ }
+ }
+
+ protected boolean validateProjectInfo(MavenProjectInfo info) {
+ if(info!=null) {
+ String projectName = getImportConfiguration().getProjectName(info.getModel());
+ if(isWorkspaceFolder(info)) {
+ setMessage(Messages.getString("wizard.import.validator.workspaceFolder", projectName), IMessageProvider.WARNING); //$NON-NLS-1$
+ } else if(isAlreadyExists(info)) {
+ setMessage(Messages.getString("wizard.import.validator.projectExists", projectName), IMessageProvider.WARNING); //$NON-NLS-1$
+ } else {
+ setMessage(null, IMessageProvider.WARNING);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected void validate() {
+ Object[] elements = projectTreeViewer.getCheckedElements();
+ for(int i = 0; i < elements.length; i++ ) {
+ Object element = elements[i];
+ if(element instanceof MavenProjectInfo) {
+ if (validateProjectInfo((MavenProjectInfo) element)) {
+ setPageComplete(false);
+ return;
+ }
+ }
+ }
+
+ setMessage(null);
+ setPageComplete(projectTreeViewer.getCheckedElements().length > 0);
+ projectTreeViewer.refresh();
+ }
+
+ /**
+ * ProjectLabelProvider
+ */
+ class ProjectLabelProvider extends LabelProvider implements IColorProvider {
+
+ public String getText(Object element) {
+ if(element instanceof MavenProjectInfo) {
+ MavenProjectInfo info = (MavenProjectInfo) element;
+
+ if(info.getProfiles().isEmpty()) {
+ return info.getLabel() + " - " + getId(info); //$NON-NLS-1$
+ }
+
+ return info.getLabel() + " - " + getId(info) + " " + info.getProfiles(); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return super.getText(element);
+ }
+
+ private String getId(MavenProjectInfo info) {
+ Model model = info.getModel();
+
+ String groupId = model.getGroupId();
+ String artifactId = model.getArtifactId();
+ String version = model.getVersion();
+ String packaging = model.getPackaging();
+
+ Parent parent = model.getParent();
+
+ if(groupId==null && parent!=null) {
+ groupId = parent.getGroupId();
+ }
+ if(groupId==null) {
+ groupId = org.eclipse.m2e.core.internal.Messages.MavenImportWizardPage_inherited;
+ }
+
+ if(version==null && parent!=null) {
+ version = parent.getVersion();
+ }
+ if(version==null) {
+ version = org.eclipse.m2e.core.internal.Messages.MavenImportWizardPage_inherited;
+ }
+
+ return groupId + ":" + artifactId + ":" + version + ":" + packaging; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object)
+ */
+ public Color getForeground(Object element) {
+ if(element instanceof MavenProjectInfo) {
+ MavenProjectInfo info = (MavenProjectInfo) element;
+ if(isWorkspaceFolder(info)) {
+ return Display.getDefault().getSystemColor(SWT.COLOR_RED);
+ } else if(isAlreadyExists(info)) {
+ return Display.getDefault().getSystemColor(SWT.COLOR_GRAY);
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object)
+ */
+ public Color getBackground(Object element) {
+ return null;
+ }
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileArtifactWizardPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileArtifactWizardPage.java
new file mode 100644
index 00000000..adbcd2a0
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileArtifactWizardPage.java
@@ -0,0 +1,390 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.io.File;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.actions.SelectionUtil;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * Wizard page to enter parameters required for artifact installation.
+ *
+ * @author Guillaume Sauthier
+ * @author Mike Haller
+ * @author Eugene Kuleshov
+ */
+public class MavenInstallFileArtifactWizardPage extends WizardPage {
+
+ Text artifactFileNameText;
+ Text pomFileNameText;
+
+ private Combo groupIdCombo;
+ private Combo artifactIdCombo;
+ private Combo versionCombo;
+ private Combo packagingCombo;
+ private Combo classifierCombo;
+
+ Button createChecksumButton;
+ Button generatePomButton;
+
+ private final IFile file;
+
+ public MavenInstallFileArtifactWizardPage(IFile file) {
+ super("mavenInstallFileWizardPage");
+ this.file = file;
+ this.setTitle(Messages.MavenInstallFileArtifactWizardPage_title);
+ this.setDescription(Messages.MavenInstallFileArtifactWizardPage_desc);
+ }
+
+ public void createControl(Composite parent) {
+ Composite container = new Composite(parent, SWT.NONE);
+ container.setLayout(new GridLayout(3, false));
+ container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ ModifyListener modifyingListener = new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ pageChanged();
+ }
+ };
+
+ Label artifactFileNameLabel = new Label(container, SWT.NONE);
+ artifactFileNameLabel.setText(Messages.MavenInstallFileArtifactWizardPage_lblFileName);
+
+ artifactFileNameText = new Text(container, SWT.BORDER);
+ artifactFileNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ artifactFileNameText.setData("name", "artifactFileNametext"); //$NON-NLS-1$ //$NON-NLS-2$
+ artifactFileNameText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ updateFileName(getArtifactFileName());
+ pageChanged();
+ }
+ });
+
+ final Button artifactFileNameButton = new Button(container, SWT.NONE);
+ artifactFileNameButton.setLayoutData(new GridData());
+ artifactFileNameButton.setData("name", "externalPomFileButton"); //$NON-NLS-1$ //$NON-NLS-2$
+ artifactFileNameButton.setText(Messages.MavenInstallFileArtifactWizardPage_btnFilename);
+ artifactFileNameButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ FileDialog fileDialog = new FileDialog(artifactFileNameButton.getShell());
+ fileDialog.setText(Messages.MavenInstallFileArtifactWizardPage_file_title);
+ fileDialog.setFileName(artifactFileNameText.getText());
+ String name = fileDialog.open();
+ if(name!=null) {
+ updateFileName(name);
+ }
+ }
+ });
+
+ Label pomFileNameLabel = new Label(container, SWT.NONE);
+ pomFileNameLabel.setText(Messages.MavenInstallFileArtifactWizardPage_lblPom);
+
+ pomFileNameText = new Text(container, SWT.BORDER);
+ pomFileNameText.setData("name", "pomFileNameText"); //$NON-NLS-1$ //$NON-NLS-2$
+ pomFileNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ pomFileNameText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ generatePomButton.setSelection(getPomFileName().length()==0);
+ pageChanged();
+ }
+ });
+
+ final Button pomFileNameButton = new Button(container, SWT.NONE);
+ pomFileNameButton.setLayoutData(new GridData());
+ pomFileNameButton.setData("name", "externalPomFileButton"); //$NON-NLS-1$ //$NON-NLS-2$
+ pomFileNameButton.setText(Messages.MavenInstallFileArtifactWizardPage_btnPom);
+ pomFileNameButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ FileDialog fileDialog = new FileDialog(pomFileNameButton.getShell());
+ fileDialog.setText(Messages.MavenInstallFileArtifactWizardPage_file_title);
+ fileDialog.setFileName(pomFileNameText.getText());
+ String res = fileDialog.open();
+ if(res!=null) {
+ pomFileNameText.setText(res);
+ }
+ }
+ });
+
+ new Label(container, SWT.NONE);
+
+ generatePomButton = new Button(container, SWT.CHECK);
+ generatePomButton.setData("name", "generatePomButton"); //$NON-NLS-1$ //$NON-NLS-2$
+ generatePomButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+ generatePomButton.setText(Messages.MavenInstallFileArtifactWizardPage_btnGenerate);
+ generatePomButton.setSelection(true);
+ new Label(container, SWT.NONE);
+
+ createChecksumButton = new Button(container, SWT.CHECK);
+ createChecksumButton.setData("name", "createChecksumButton"); //$NON-NLS-1$ //$NON-NLS-2$
+ createChecksumButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+ createChecksumButton.setText(Messages.MavenInstallFileArtifactWizardPage_btnChecksum);
+ createChecksumButton.setSelection(true);
+
+ Label separator = new Label(container, SWT.HORIZONTAL | SWT.SEPARATOR);
+ GridData separatorData = new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1);
+ separatorData.verticalIndent = 5;
+ separator.setLayoutData(separatorData);
+
+ Label groupIdlabel = new Label(container, SWT.NONE);
+ groupIdlabel.setText(Messages.MavenInstallFileArtifactWizardPage_lblgroupid);
+
+ groupIdCombo = new Combo(container, SWT.NONE);
+ groupIdCombo.setData("name", "groupIdCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+ groupIdCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ groupIdCombo.addModifyListener(modifyingListener);
+ new Label(container, SWT.NONE);
+
+ Label artifactIdLabel = new Label(container, SWT.NONE);
+ artifactIdLabel.setText(Messages.MavenInstallFileArtifactWizardPage_lblArtifact);
+
+ artifactIdCombo = new Combo(container, SWT.NONE);
+ artifactIdCombo.setData("name", "artifactIdCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+ artifactIdCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ artifactIdCombo.addModifyListener(modifyingListener);
+ new Label(container, SWT.NONE);
+
+ Label versionLabel = new Label(container, SWT.NONE);
+ versionLabel.setText(Messages.MavenInstallFileArtifactWizardPage_lblVersion);
+
+ versionCombo = new Combo(container, SWT.NONE);
+ versionCombo.setData("name", "versionCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+ versionCombo.setText(MavenArtifactComponent.DEFAULT_VERSION);
+ GridData versionComboData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
+ versionComboData.widthHint = 150;
+ versionCombo.setLayoutData(versionComboData);
+ versionCombo.addModifyListener(modifyingListener);
+
+ Label packagingLabel = new Label(container, SWT.NONE);
+ packagingLabel.setText(Messages.MavenInstallFileArtifactWizardPage_lblPackaging);
+
+ packagingCombo = new Combo(container, SWT.NONE);
+ packagingCombo.setData("name", "packagingCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+ packagingCombo.setText(MavenArtifactComponent.DEFAULT_PACKAGING);
+ packagingCombo.setItems(MavenArtifactComponent.PACKAGING_OPTIONS);
+ GridData packagingComboData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
+ packagingComboData.widthHint = 150;
+ packagingCombo.setLayoutData(packagingComboData);
+ packagingCombo.addModifyListener(modifyingListener);
+
+ Label classifierLabel = new Label(container, SWT.NONE);
+ classifierLabel.setText(Messages.MavenInstallFileArtifactWizardPage_lblClassifier);
+
+ classifierCombo = new Combo(container, SWT.NONE);
+ classifierCombo.setData("name", "classifierText"); //$NON-NLS-1$ //$NON-NLS-2$
+ classifierCombo.setItems(new String[] {"sources", "javadoc"}); //$NON-NLS-1$ //$NON-NLS-2$
+ GridData classifierTextData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
+ classifierTextData.widthHint = 150;
+ classifierCombo.setLayoutData(classifierTextData);
+ classifierCombo.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ generatePomButton.setSelection(getClassifier().length()==0);
+ }
+ });
+
+ if(file != null) {
+ updateFileName(file.getLocation().toOSString());
+ }
+
+ setControl(container);
+ }
+
+ void updateFileName(String fileName) {
+ if(!getArtifactFileName().equals(fileName)) {
+ artifactFileNameText.setText(fileName);
+ }
+
+ File file = new File(fileName);
+ if(!file.exists() || !file.isFile()) {
+ return;
+ }
+
+ if(fileName.endsWith(".jar") || fileName.endsWith(".war") || fileName.endsWith(".ear")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ packagingCombo.setText(fileName.substring(fileName.length()-3));
+ }
+
+ int n = fileName.lastIndexOf('.');
+ if(n>-1) {
+ String pomFileName = fileName.substring(0, n) + ".pom"; //$NON-NLS-1$
+ if(new File(pomFileName).exists()) {
+ pomFileNameText.setText(pomFileName);
+ }
+ } else {
+ pomFileNameText.setText(""); //$NON-NLS-1$
+ }
+
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ try {
+ IndexedArtifactFile iaf = plugin.getIndexManager().getAllIndexes().identify(file);
+ if(iaf!=null) {
+ groupIdCombo.setText(iaf.group);
+ artifactIdCombo.setText(iaf.artifact);
+ versionCombo.setText(iaf.version);
+ if(iaf.classifier!=null) {
+ classifierCombo.setText(iaf.classifier);
+ }
+
+ String name = iaf.group + ":" + iaf.artifact + "-" + iaf.version // //$NON-NLS-1$ //$NON-NLS-2$
+ + (iaf.classifier == null ? "" : iaf.classifier); //$NON-NLS-1$
+ setMessage(NLS.bind(Messages.MavenInstallFileArtifactWizardPage_message, name), WARNING);
+ return;
+ }
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+
+ if(n>-1) {
+ String pomFileName = fileName.substring(0, n) + ".pom"; //$NON-NLS-1$
+ if(new File(pomFileName).exists()) {
+ pomFileNameText.setText(pomFileName);
+
+ // read pom file
+
+ try {
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+ MavenProject mavenProject = maven.readProject(new File(pomFileName), null);
+
+ groupIdCombo.setText(mavenProject.getGroupId());
+ artifactIdCombo.setText(mavenProject.getArtifactId());
+ versionCombo.setText(mavenProject.getVersion());
+ packagingCombo.setText(mavenProject.getPackaging());
+ return;
+
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ }
+
+ ArtifactKey artifactKey = SelectionUtil.getType(file, ArtifactKey.class);
+ if(artifactKey!=null) {
+ groupIdCombo.setText(artifactKey.getGroupId());
+ artifactIdCombo.setText(artifactKey.getArtifactId());
+ versionCombo.setText(artifactKey.getVersion());
+ if(artifactKey.getClassifier()!=null) {
+ classifierCombo.setText(artifactKey.getClassifier());
+ }
+ }
+ }
+
+ void pageChanged() {
+ String artifactFileName = getArtifactFileName();
+ if(artifactFileName.length() == 0) {
+ updateStatus(Messages.MavenInstallFileArtifactWizardPage_error_no_name);
+ return;
+ }
+
+ File file = new File(artifactFileName);
+ if(!file.exists() || !file.isFile()) {
+ updateStatus(Messages.MavenInstallFileArtifactWizardPage_error_missing);
+ return;
+ }
+
+ String pomFileName = getPomFileName();
+ if(pomFileName.length()>0) {
+ if(!new File(pomFileName).exists()) {
+ updateStatus(Messages.MavenInstallFileArtifactWizardPage_error_missingpom);
+ return;
+ }
+ }
+
+ if(getGroupId().length() == 0) {
+ updateStatus(Messages.MavenInstallFileArtifactWizardPage_error_groupid);
+ return;
+ }
+
+ if(getArtifactId().length() == 0) {
+ updateStatus(Messages.MavenInstallFileArtifactWizardPage_error_artifactid);
+ return;
+ }
+
+ if(getVersion().length() == 0) {
+ updateStatus(Messages.MavenInstallFileArtifactWizardPage_error_version);
+ return;
+ }
+
+ if(getPackaging().length() == 0) {
+ updateStatus(Messages.MavenInstallFileArtifactWizardPage_error_packaging);
+ return;
+ }
+
+ updateStatus(null);
+ }
+
+ private void updateStatus(String message) {
+ setErrorMessage(message);
+ setPageComplete(message == null);
+ }
+
+ public String getArtifactFileName() {
+ return artifactFileNameText.getText().trim();
+ }
+
+ public String getPomFileName() {
+ return pomFileNameText.getText().trim();
+ }
+
+ public String getGroupId() {
+ return groupIdCombo.getText().trim();
+ }
+
+ public String getArtifactId() {
+ return artifactIdCombo.getText().trim();
+ }
+
+ public String getVersion() {
+ return versionCombo.getText().trim();
+ }
+
+ public String getPackaging() {
+ return packagingCombo.getText().trim();
+ }
+
+ public String getClassifier() {
+ return this.classifierCombo.getText().trim();
+ }
+
+ public boolean isGeneratePom() {
+ return generatePomButton.getSelection();
+ }
+
+ public boolean isCreateChecksum() {
+ return createChecksumButton.getSelection();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileRepositoryWizardPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileRepositoryWizardPage.java
new file mode 100644
index 00000000..ef199a8f
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileRepositoryWizardPage.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.io.File;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.model.edit.pom.Model;
+import org.eclipse.m2e.model.edit.pom.PomFactory;
+import org.eclipse.m2e.model.edit.pom.Repository;
+
+
+/**
+ * MavenInstallFileRepositoryWizardPage used to chose to repositories for installing artifacts.
+ *
+ * @author Mike Haller
+ */
+public class MavenInstallFileRepositoryWizardPage extends WizardPage {
+
+ private final IFile pomFile;
+
+ public MavenInstallFileRepositoryWizardPage(IFile pomFile) {
+ super("mavenInstallFileRepositorySelectionPage");
+ setTitle("Repository Selection Page");
+ setDescription("Select the repositories where to deploy the artifact");
+ this.pomFile = pomFile;
+ }
+
+ public void createControl(Composite parent) {
+ Composite container = new Composite(parent, SWT.NONE);
+ container.setLayout(new GridLayout(1, false));
+ container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ Label repositoriesLabel = new Label(container, SWT.NONE);
+ repositoriesLabel.setData("name", "repositoriesLabel");
+ repositoriesLabel.setText("&Repositories:");
+
+ CheckboxTreeViewer repositoryViewer = new CheckboxTreeViewer(container, SWT.BORDER);
+ repositoryViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ // repositoryViewer.setInput(pomFile);
+ repositoryViewer.setLabelProvider(new RepositoryLabelProvider());
+ repositoryViewer.setContentProvider(new RepositoriesContentProvider());
+ repositoryViewer.setCheckedElements(new Object[] {RepositoriesContentProvider.LOCAL_REPOSITORY});
+
+ initRepositories();
+
+ setControl(container);
+ }
+
+ private void initRepositories() {
+ // TODO Auto-generated method initRepositories
+
+ }
+
+ /**
+ * RepositoryLabelProvider prints the name of a repository, and if available, its URL.
+ */
+ public class RepositoryLabelProvider extends LabelProvider {
+
+ public String getText(Object element) {
+ if(element instanceof Repository) {
+ Repository repository = (Repository) element;
+ if(repository.getUrl() != null && repository.getUrl().trim().length() > 0) {
+ return repository.getName() + "(" + repository.getUrl() + ")";
+ }
+ return repository.getName();
+ }
+ return super.getText(element);
+ }
+
+ }
+
+ /**
+ * LocalRepositoriesContentProvider provides a list of local and remote repositories.
+ * <p>
+ * If no repositories could be found in the POM Maven Model, a default local repository is shown.
+ */
+ public static class RepositoriesContentProvider implements ITreeContentProvider {
+
+ public static final Repository LOCAL_REPOSITORY = createLocalRepository();
+
+ private static Repository createLocalRepository() {
+ Repository repository = PomFactory.eINSTANCE.createRepository();
+ repository.setId("local");
+ repository.setName("Local Repository");
+ try {
+ File localRepositoryDir = new File(MavenPlugin.getDefault().getMaven().getLocalRepository().getBasedir());
+ repository.setUrl(localRepositoryDir.toURI().toString());
+ } catch(CoreException ex) {
+ MavenLogger.log("Unable to determine local repository URL, using default", ex);
+ }
+ return repository;
+ }
+
+ public Object[] getElements(Object arg0) {
+ return repositories.toArray();
+ }
+
+ private EList<Repository> repositories;
+
+ public Object[] getChildren(Object arg0) {
+ return null;
+ }
+
+ public Object getParent(Object arg0) {
+ return null;
+ }
+
+ public boolean hasChildren(Object arg0) {
+ return false;
+ }
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer arg0, Object arg1, Object newInput) {
+ if(newInput instanceof Model) {
+ Model model = (Model) newInput;
+ repositories = model.getRepositories();
+ }
+ }
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileWizard.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileWizard.java
new file mode 100644
index 00000000..23212884
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenInstallFileWizard.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IImportWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.progress.IProgressConstants;
+
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionResult;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.actions.OpenMavenConsoleAction;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * Wizard to install artifacts into the local Maven repository.
+ *
+ * @author Guillaume Sauthier
+ * @author Mike Haller
+ * @author Eugene Kuleshov
+ * @since 0.9.7
+ */
+public class MavenInstallFileWizard extends Wizard implements IImportWizard {
+
+ private IFile selectedFile;
+
+ private IFile pomFile;
+
+ private MavenInstallFileArtifactWizardPage artifactPage;
+
+ private MavenInstallFileRepositoryWizardPage repositoryPage;
+
+ public MavenInstallFileWizard() {
+ setNeedsProgressMonitor(true);
+ setWindowTitle(Messages.MavenInstallFileWizard_title);
+ }
+
+ public void addPages() {
+ artifactPage = new MavenInstallFileArtifactWizardPage(selectedFile);
+ addPage(artifactPage);
+
+ // repositoryPage = new MavenInstallFileRepositoryWizardPage(pomFile);
+ // addPage(repositoryPage);
+ }
+
+ public boolean performFinish() {
+ final Properties properties = new Properties();
+
+ // Mandatory Properties for install:install-file
+ properties.setProperty("file", artifactPage.getArtifactFileName()); //$NON-NLS-1$
+
+ properties.setProperty("groupId", artifactPage.getGroupId()); //$NON-NLS-1$
+ properties.setProperty("artifactId", artifactPage.getArtifactId()); //$NON-NLS-1$
+ properties.setProperty("version", artifactPage.getVersion()); //$NON-NLS-1$
+ properties.setProperty("packaging", artifactPage.getPackaging()); //$NON-NLS-1$
+
+ if(artifactPage.getClassifier().length()>0) {
+ properties.setProperty("classifier", artifactPage.getClassifier()); //$NON-NLS-1$
+ }
+
+ if(artifactPage.getPomFileName().length()>0) {
+ properties.setProperty("pomFile", artifactPage.getPomFileName()); //$NON-NLS-1$
+ }
+ if(artifactPage.isGeneratePom()) {
+ properties.setProperty("generatePom", "true"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if(artifactPage.isCreateChecksum()) {
+ properties.setProperty("createChecksum", "true"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ new Job(Messages.MavenInstallFileWizard_job) {
+ protected IStatus run(IProgressMonitor monitor) {
+ setProperty(IProgressConstants.ACTION_PROPERTY, new OpenMavenConsoleAction());
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ try {
+ // Run the install:install-file goal
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+ MavenExecutionRequest request = maven.createExecutionRequest(monitor);
+ request.setGoals(Arrays.asList("install:install-file")); //$NON-NLS-1$
+ request.setUserProperties(properties);
+ MavenExecutionResult executionResult = maven.execute(request, monitor);
+
+ List<Throwable> exceptions = executionResult.getExceptions();
+ if(!exceptions.isEmpty()) {
+ for(Throwable exception : exceptions) {
+ String msg = Messages.MavenInstallFileWizard_error;
+ plugin.getConsole().logError(msg + "; " + exception.toString()); //$NON-NLS-1$
+ MavenLogger.log(msg, exception);
+ }
+ }
+
+ // TODO update index for local maven repository
+
+ } catch (CoreException ex) {
+ MavenLogger.log(ex);
+ plugin.getConsole().logError("Failed to install artifact");
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+
+ return true;
+ }
+
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ Object element = selection.getFirstElement();
+ if(element instanceof IFile) {
+ selectedFile = (IFile) element;
+ setPomFile(selectedFile.getProject());
+ } else if(element instanceof IProject) {
+ setPomFile((IProject) element);
+ }
+ }
+
+ private void setPomFile(IProject project) {
+ if(project.isAccessible()) {
+ IFile pomFile = project.getFile(IMavenConstants.POM_FILE_NAME);
+ if(pomFile!=null && pomFile.isAccessible()) {
+ this.pomFile = pomFile;
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenLocationComponent.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenLocationComponent.java
new file mode 100644
index 00000000..534dcdfe
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenLocationComponent.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+
+import org.eclipse.m2e.core.core.Messages;
+
+
+/**
+ * Simple GUI component which allows the user to choose between a workspace
+ * location and a user specified external location.
+ *
+ * This component is mainly used for choosing the location at which to create
+ * a new project.
+ */
+public class MavenLocationComponent extends Composite {
+
+ /** Radio button indicating whether the workspace location has been chosen. */
+ protected Button inWorkspaceButton;
+
+ /** Radio button indicating whether an external location has been chosen. */
+ protected Button inExternalLocationButton;
+
+ /** Text field for defining a user specified external location. */
+ protected Combo locationCombo;
+
+ /** Button allowing to choose a directory on the file system as the external location. */
+ protected Button locationBrowseButton;
+
+ protected ModifyListener modifyingListener;
+
+ protected Label locationLabel;
+
+ /**
+ * Constructor.
+ *
+ * Constructs all the GUI components contained in this <code>Composite</code>.
+ * These components allow the user to choose between a workspace location and
+ * a user specified external location.
+ *
+ * @param parent The widget which will be the parent of this component.
+ * @param styles The widget style for this component.
+ * @param modifyingListener Listener which is notified when the contents of
+ * this component change due to user input.
+ */
+ public MavenLocationComponent( final Composite parent, int styles ) {
+ super( parent, styles );
+
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ setLayout( gridLayout );
+
+ Group locationGroup = new Group( this, SWT.NONE );
+ locationGroup.setText( Messages.getString( "locationComponent.location" ) ); //$NON-NLS-1$
+ locationGroup.setLayoutData( new GridData( GridData.FILL, GridData.FILL, true, true, 3, 1 ) );
+ GridLayout groupLayout = new GridLayout();
+ groupLayout.numColumns = 3;
+ groupLayout.marginLeft = 0;
+ locationGroup.setLayout( groupLayout );
+
+ GridData gridData = new GridData();
+ gridData.horizontalSpan = 3;
+
+ // first radio button
+ inWorkspaceButton = new Button( locationGroup, SWT.RADIO );
+ inWorkspaceButton.setText( Messages.getString( "locationComponent.inWorkspace" ) ); //$NON-NLS-1$
+ inWorkspaceButton.setLayoutData( new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1) );
+ inWorkspaceButton.addSelectionListener( new SelectionAdapter() {
+ public void widgetSelected( SelectionEvent e ) {
+ boolean isEnabled = !inWorkspaceButton.getSelection();
+ locationLabel.setEnabled( isEnabled );
+ locationCombo.setEnabled( isEnabled );
+ locationBrowseButton.setEnabled( isEnabled );
+ if(modifyingListener!=null) {
+ modifyingListener.modifyText( null );
+ }
+ }
+ } );
+
+ // second radio button
+ inExternalLocationButton = new Button( locationGroup, SWT.RADIO );
+ inExternalLocationButton.setText( Messages.getString( "locationComponent.atExternal" ) ); //$NON-NLS-1$
+ inExternalLocationButton.setLayoutData( gridData );
+
+ // choose directory
+ locationLabel = new Label( locationGroup, SWT.NONE );
+ GridData gd_locationLabel = new GridData();
+ gd_locationLabel.horizontalIndent = 10;
+ locationLabel.setLayoutData(gd_locationLabel);
+ locationLabel.setText( Messages.getString( "locationComponent.directory" ) ); //$NON-NLS-1$
+
+ locationCombo = new Combo( locationGroup, SWT.BORDER );
+ locationCombo.setLayoutData( new GridData( GridData.FILL_HORIZONTAL ) );
+
+ locationBrowseButton = new Button( locationGroup, SWT.PUSH );
+ locationBrowseButton.setText( Messages.getString( "locationComponent.browse" ) ); //$NON-NLS-1$
+
+ gridData = new GridData( SWT.FILL, SWT.DEFAULT, false, false );
+ locationBrowseButton.setLayoutData( gridData );
+
+ locationBrowseButton.addSelectionListener( new SelectionAdapter() {
+ public void widgetSelected( SelectionEvent e ) {
+ DirectoryDialog dialog = new DirectoryDialog(getShell());
+ dialog.setText(Messages.getString( "locationComponent.selectLocation" )); //$NON-NLS-1$
+
+ String path = locationCombo.getText();
+ if(path.length()==0) {
+ path = ResourcesPlugin.getWorkspace().getRoot().getLocation().toPortableString();
+ }
+ dialog.setFilterPath(path);
+
+ String selectedDir = dialog.open();
+ if(selectedDir != null) {
+ locationCombo.setText( selectedDir.trim() );
+ }
+ }
+ } );
+
+ inWorkspaceButton.setSelection( true );
+
+ locationLabel.setEnabled( false );
+ locationCombo.setEnabled( false );
+ locationBrowseButton.setEnabled( false );
+ }
+
+ /**
+ * Returns the path of the location chosen by the user.
+ *
+ * According to the user input, the path either points to the workspace or
+ * to a valid user specified location on the filesystem.
+ *
+ * @return The path of the location chosen by the user.
+ * Is never <code>null</code>.
+ */
+ public IPath getLocationPath() {
+ if ( isInWorkspace() ) {
+ return Platform.getLocation();
+ }
+ return Path.fromOSString( locationCombo.getText().trim() );
+ }
+
+ /**
+ * Returns whether the workspace has been chosen as the location to use.
+ *
+ * @return <code>true</code> if the workspace is chosen as the location to use,
+ * <code>false</code> if the specified external location is to be used.
+ */
+ public boolean isInWorkspace() {
+ return inWorkspaceButton.getSelection();
+ }
+
+ public void setModifyingListener( ModifyListener modifyingListener ) {
+ this.modifyingListener = modifyingListener;
+ locationCombo.addModifyListener( modifyingListener );
+ }
+
+ public Combo getLocationCombo() {
+ return locationCombo;
+ }
+
+ public void dispose() {
+ super.dispose();
+ if(modifyingListener!=null) {
+ locationCombo.removeModifyListener( modifyingListener );
+ }
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenMaterializePomWizard.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenMaterializePomWizard.java
new file mode 100644
index 00000000..920ab4ef
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenMaterializePomWizard.java
@@ -0,0 +1,241 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IImportWizard;
+import org.eclipse.ui.INewWizard;
+import org.eclipse.ui.IWorkbench;
+
+import org.apache.maven.model.Dependency;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.actions.SelectionUtil;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.MavenProjectPomScanner;
+import org.eclipse.m2e.core.project.MavenProjectScmInfo;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+
+
+/**
+ * A wizard used to import projects for Maven artifacts
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenMaterializePomWizard extends Wizard implements IImportWizard, INewWizard {
+
+ ProjectImportConfiguration importConfiguration;
+
+ MavenDependenciesWizardPage selectionPage;
+
+ MavenProjectWizardLocationPage locationPage;
+
+ Button checkOutAllButton;
+
+ Button useDeveloperConnectionButton;
+
+ // TODO replace with ArtifactKey
+ private Dependency[] dependencies;
+
+ private IStructuredSelection selection;
+
+
+ public MavenMaterializePomWizard() {
+ importConfiguration = new ProjectImportConfiguration();
+ setNeedsProgressMonitor(true);
+ setWindowTitle(Messages.MavenMaterializePomWizard_title);
+ }
+
+ public void setDependencies(Dependency[] dependencies) {
+ this.dependencies = dependencies;
+ }
+
+ public Dependency[] getDependencies() {
+ return dependencies;
+ }
+
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ this.selection = selection;
+
+ importConfiguration.setWorkingSet(SelectionUtil.getSelectedWorkingSet(selection));
+
+ ArrayList<Dependency> dependencies = new ArrayList<Dependency>();
+
+ for(Iterator<?> it = selection.iterator(); it.hasNext();) {
+ Object element = it.next();
+ ArtifactKey artifactKey = SelectionUtil.getType(element, ArtifactKey.class);
+ if(artifactKey!=null) {
+ Dependency d = new Dependency();
+ d.setGroupId(artifactKey.getGroupId());
+ d.setArtifactId(artifactKey.getArtifactId());
+ d.setVersion(artifactKey.getVersion());
+ d.setClassifier(artifactKey.getClassifier());
+ dependencies.add(d);
+ }
+ }
+
+ setDependencies(dependencies.toArray(new Dependency[dependencies.size()]));
+ }
+
+ public void addPages() {
+ selectionPage = new MavenDependenciesWizardPage(importConfiguration, //
+ Messages.MavenMaterializePomWizard_dialog_title, //
+ Messages.MavenMaterializePomWizard_dialog_message) {
+ protected void createAdvancedSettings(Composite composite, GridData gridData) {
+ checkOutAllButton = new Button(composite, SWT.CHECK);
+ checkOutAllButton.setText(Messages.MavenMaterializePomWizard_btnCheckout);
+ checkOutAllButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 3, 1));
+
+ useDeveloperConnectionButton = new Button(composite, SWT.CHECK);
+ useDeveloperConnectionButton.setText(Messages.MavenMaterializePomWizard_btnDev);
+ useDeveloperConnectionButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 3, 1));
+
+ super.createAdvancedSettings(composite, gridData);
+ }
+ };
+ selectionPage.setDependencies(dependencies);
+
+ locationPage = new MavenProjectWizardLocationPage(importConfiguration, //
+ Messages.MavenMaterializePomWizard_location_title,
+ Messages.MavenMaterializePomWizard_location_message);
+ locationPage.setLocationPath(SelectionUtil.getSelectedLocation(selection));
+
+ addPage(selectionPage);
+ addPage(locationPage);
+ }
+
+ public boolean canFinish() {
+ return super.canFinish();
+ }
+
+ public boolean performFinish() {
+ if(!canFinish()) {
+ return false;
+ }
+
+ final Dependency[] dependencies = selectionPage.getDependencies();
+
+ final boolean checkoutAllProjects = checkOutAllButton.getSelection();
+ final boolean developer = useDeveloperConnectionButton.getSelection();
+
+ MavenProjectCheckoutJob job = new MavenProjectCheckoutJob(importConfiguration, checkoutAllProjects) {
+ protected List<MavenProjectScmInfo> getProjects(IProgressMonitor monitor) throws InterruptedException {
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ MavenProjectPomScanner<MavenProjectScmInfo> scanner = new MavenProjectPomScanner<MavenProjectScmInfo>(developer, dependencies, //
+ plugin.getMavenModelManager(), //
+ plugin.getConsole());
+ scanner.run(monitor);
+ // XXX handle errors/warnings
+
+ return scanner.getProjects();
+ }
+ };
+
+ if(!locationPage.isInWorkspace()) {
+ job.setLocation(locationPage.getLocationPath().toFile());
+ }
+
+ job.schedule();
+
+ return true;
+ }
+
+// public Scm[] getScms(IProgressMonitor monitor) {
+// ArrayList scms = new ArrayList();
+//
+// MavenPlugin plugin = MavenPlugin.getDefault();
+// MavenEmbedderManager embedderManager = plugin.getMavenEmbedderManager();
+// IndexManager indexManager = plugin.getMavenRepositoryIndexManager();
+// MavenConsole console = plugin.getConsole();
+//
+// MavenEmbedder embedder = embedderManager.getWorkspaceEmbedder();
+//
+// for(int i = 0; i < dependencies.length; i++ ) {
+// try {
+// Dependency d = dependencies[i];
+//
+// Artifact artifact = embedder.createArtifact(d.getGroupId(), //
+// d.getArtifactId(), d.getVersion(), null, "pom");
+//
+// List remoteRepositories = indexManager.getArtifactRepositories(null, null);
+//
+// embedder.resolve(artifact, remoteRepositories, embedder.getLocalRepository());
+//
+// File file = artifact.getFile();
+// if(file != null) {
+// MavenProject project = embedder.readProject(file);
+//
+// Scm scm = project.getScm();
+// if(scm == null) {
+// String msg = project.getId() + " doesn't specify SCM info";
+// console.logError(msg);
+// continue;
+// }
+//
+// String connection = scm.getConnection();
+// String devConnection = scm.getDeveloperConnection();
+// String tag = scm.getTag();
+// String url = scm.getUrl();
+//
+// console.logMessage(project.getArtifactId());
+// console.logMessage("Connection: " + connection);
+// console.logMessage(" dev: " + devConnection);
+// console.logMessage(" url: " + url);
+// console.logMessage(" tag: " + tag);
+//
+// if(connection==null) {
+// if(devConnection==null) {
+// String msg = project.getId() + " doesn't specify SCM connection";
+// console.logError(msg);
+// continue;
+// }
+// scm.setConnection(devConnection);
+// }
+//
+// // connection: scm:svn:https://svn.apache.org/repos/asf/incubator/wicket/branches/wicket-1.2.x/wicket
+// // dev: scm:svn:https://svn.apache.org/repos/asf/incubator/wicket/branches/wicket-1.2.x/wicket
+// // url: http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.2.x/wicket
+// // tag: HEAD
+//
+// // TODO add an option to select all modules/projects and optimize scan
+//
+// scms.add(scm);
+//
+//// if(!connection.startsWith(SCM_SVN_PROTOCOL)) {
+//// String msg = project.getId() + " SCM type is not supported " + connection;
+//// console.logError(msg);
+//// addError(new Exception(msg));
+//// } else {
+//// String svnUrl = connection.trim().substring(SCM_SVN_PROTOCOL.length());
+//// }
+// }
+//
+// } catch(Exception ex) {
+// console.logError(ex.getMessage());
+// }
+// }
+//
+// return (Scm[]) scms.toArray(new Scm[scms.size()]);
+// }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenModuleWizard.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenModuleWizard.java
new file mode 100644
index 00000000..d9028c09
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenModuleWizard.java
@@ -0,0 +1,305 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.resources.WorkspaceJob;
+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.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.INewWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.progress.IProgressConstants;
+
+import org.apache.maven.archetype.catalog.Archetype;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Parent;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.actions.OpenMavenConsoleAction;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+
+
+/**
+ * A project wizard for creating a new Maven2 module project.
+ */
+public class MavenModuleWizard extends Wizard implements INewWizard {
+
+ /** The name of the default wizard page image. */
+ // protected static final String DEFAULT_PAGE_IMAGE_NAME = "icons/new_m2_project_wizard.gif";
+
+ /** The default wizard page image. */
+ // protected static final ImageDescriptor DEFAULT_PAGE_IMAGE = MavenPlugin.getImageDescriptor(DEFAULT_PAGE_IMAGE_NAME);
+
+ /** the current selection */
+ private IStructuredSelection selection;
+
+ /** the parent page (#1) */
+ protected MavenModuleWizardParentPage parentPage;
+
+ /** The archetype selection page. */
+ protected MavenProjectWizardArchetypePage archetypePage;
+
+ /** The wizard page for gathering Maven2 project information. */
+ protected MavenProjectWizardArtifactPage artifactPage;
+
+ /** The wizard page for gathering archetype project information. */
+ protected MavenProjectWizardArchetypeParametersPage parametersPage;
+
+ /** The wizard page for choosing the Maven2 dependencies to use. */
+ private MavenDependenciesWizardPage dependenciesPage;
+
+ /** The project configuration bean. */
+ protected ProjectImportConfiguration configuration;
+
+ private String moduleName;
+
+ protected boolean isEditor = false;
+
+ /** Default constructor. Sets the title and image of the wizard. */
+ public MavenModuleWizard() {
+ setWindowTitle(Messages.getString("wizard.module.title")); //$NON-NLS-1$
+ setDefaultPageImageDescriptor(MavenImages.WIZ_NEW_PROJECT);
+ setNeedsProgressMonitor(true);
+ }
+
+ public MavenModuleWizard(boolean isEditor) {
+ this();
+ this.isEditor = isEditor;
+ }
+
+ /** Creates the pages. */
+ public void addPages() {
+ configuration = new ProjectImportConfiguration();
+
+ parentPage = new MavenModuleWizardParentPage(configuration);
+ archetypePage = new MavenProjectWizardArchetypePage(configuration);
+ parametersPage = new MavenProjectWizardArchetypeParametersPage(configuration);
+ artifactPage = new MavenProjectWizardArtifactPage(configuration);
+ dependenciesPage = new MavenDependenciesWizardPage(configuration, //
+ Messages.getString("wizard.project.page.dependencies.title"), // //$NON-NLS-1$
+ Messages.getString("wizard.project.page.dependencies.description")); //$NON-NLS-1$
+ dependenciesPage.setDependencies(new Dependency[0]);
+ dependenciesPage.setShowScope(true);
+
+ addPage(parentPage);
+ addPage(archetypePage);
+ addPage(parametersPage);
+ addPage(artifactPage);
+ addPage(dependenciesPage);
+ }
+
+ /** Adds the listeners after the page controls are created. */
+ public void createPageControls(Composite pageContainer) {
+ artifactPage.setParentReadonly(true);
+ artifactPage.setTitle(Messages.getString("wizard.module.page.artifact.title")); //$NON-NLS-1$
+ archetypePage.setTitle(Messages.getString("wizard.module.page.archetype.title")); //$NON-NLS-1$
+ parametersPage.setTitle(Messages.getString("wizard.module.page.parameters.title")); //$NON-NLS-1$
+
+ super.createPageControls(pageContainer);
+
+ parametersPage.setArtifactIdEnabled(false);
+
+ parentPage.addArchetypeSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ archetypePage.setUsed(!parentPage.isSimpleProject());
+ }
+ });
+
+ parentPage.addModuleNameListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ parametersPage.setProjectName(parentPage.getModuleName());
+ artifactPage.setProjectName(parentPage.getModuleName());
+ }
+ });
+
+ parentPage.addParentProjectListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ copyParentValues();
+ }
+ });
+
+ if(selection != null && selection.size() > 0) {
+ parentPage.setParent(selection.getFirstElement());
+ copyParentValues();
+ }
+ }
+
+ /** Copies the parent project parameters to the artifact page. */
+ protected void copyParentValues() {
+ Model model = parentPage.getParentModel();
+ if(model != null) {
+ String groupId = model.getGroupId();
+ String artifactId = model.getArtifactId();
+ String version = model.getVersion();
+
+ if(groupId == null) {
+ Parent parent = model.getParent();
+ if(parent != null) {
+ groupId = parent.getGroupId();
+ }
+ }
+ if(version == null) {
+ Parent parent = model.getParent();
+ if(parent != null) {
+ version = parent.getVersion();
+ }
+ }
+
+ artifactPage.setParentProject(groupId, artifactId, version);
+ parametersPage.setParentProject(groupId, artifactId, version);
+ }
+ }
+
+ /** Stores the current selection. */
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ this.selection = selection;
+ }
+
+ /** Performs the "finish" action. */
+ public boolean performFinish() {
+ // First of all, we extract all the information from the wizard pages.
+ // Note that this should not be done inside the operation we will run
+ // since many of the wizard pages' methods can only be invoked from within
+ // the SWT event dispatcher thread. However, the operation spawns a new
+ // separate thread to perform the actual work, i.e. accessing SWT elements
+ // from within that thread would lead to an exception.
+
+ final String moduleName = parentPage.getModuleName();
+
+ // Get the location where to create the project. For some reason, when using
+ // the default workspace location for a project, we have to pass null
+ // instead of the actual location.
+ final IPath location = parentPage.getParentContainer().getLocation();
+
+ final IFile parentPom = parentPage.getPom();
+
+ Job job;
+
+ final MavenPlugin plugin = MavenPlugin.getDefault();
+
+ if(parentPage.isSimpleProject()) {
+
+ final Model model = artifactPage.getModel();
+ @SuppressWarnings("unchecked")
+ List<Dependency> modelDependencies = model.getDependencies();
+ modelDependencies.addAll(Arrays.asList(dependenciesPage.getDependencies()));
+
+ final String[] folders = artifactPage.getFolders();
+
+ job = new WorkspaceJob(Messages.getString("wizard.project.job.creatingProject", moduleName)) { //$NON-NLS-1$
+ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
+ setProperty(IProgressConstants.ACTION_PROPERTY, new OpenMavenConsoleAction());
+ String projectName = configuration.getProjectName(model);
+ IProject project = configuration.getProject(ResourcesPlugin.getWorkspace().getRoot(), model);
+
+ // XXX respect parent's setting for separate projects for modules
+ // XXX should run update sources on parent instead of creating new module project
+
+ plugin.getProjectConfigurationManager().createSimpleProject(project, location.append(moduleName), model,
+ folders, configuration, monitor);
+
+ setModule(projectName);
+
+ return Status.OK_STATUS;
+ }
+ };
+
+ } else {
+ Model model = parametersPage.getModel();
+
+ final IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(moduleName);
+ final Archetype archetype = archetypePage.getArchetype();
+
+ final String groupId = model.getGroupId();
+ final String artifactId = model.getArtifactId();
+ final String version = model.getVersion();
+ final String javaPackage = parametersPage.getJavaPackage();
+ final Properties properties = parametersPage.getProperties();
+
+ job = new WorkspaceJob(Messages.getString("wizard.project.job.creating", archetype.getArtifactId())) { //$NON-NLS-1$
+ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
+ setProperty(IProgressConstants.ACTION_PROPERTY, new OpenMavenConsoleAction());
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ plugin.getProjectConfigurationManager().createArchetypeProject(project, location, archetype, //
+ groupId, artifactId, version, javaPackage, properties, configuration, monitor);
+
+ setModule(moduleName);
+
+ return Status.OK_STATUS;
+ }
+ };
+ }
+ job.addJobChangeListener(new JobChangeAdapter() {
+ public void done(IJobChangeEvent event) {
+ final IStatus result = event.getResult();
+ if(result.isOK()) {
+ if(!isEditor) {
+ plugin.getMavenModelManager().addModule(parentPom, moduleName);
+ }
+
+ } else {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ MessageDialog.openError(getShell(), //
+ Messages.getString("wizard.project.job.failed", moduleName), // //$NON-NLS-1$
+ result.getMessage());
+ }
+ });
+ }
+ }
+ });
+ job.setRule(plugin.getProjectConfigurationManager().getRule());
+ job.schedule();
+
+ if(isEditor) {
+ try {
+ job.join();
+ } catch(InterruptedException ex) {
+ // ignore
+ }
+ }
+
+ return true;
+ }
+
+ void setModule(String moduleName) {
+ this.moduleName = moduleName;
+ }
+
+ public String getModuleName() {
+ return this.moduleName;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenModuleWizardParentPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenModuleWizardParentPage.java
new file mode 100644
index 00000000..4b2c1b14
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenModuleWizardParentPage.java
@@ -0,0 +1,310 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+import org.apache.maven.model.Model;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.actions.SelectionUtil;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+
+
+/**
+ * Maven2ModuleParentPage
+ */
+public class MavenModuleWizardParentPage extends AbstractMavenWizardPage {
+
+ /** the module name input field */
+ private Combo moduleNameCombo;
+
+ /** the parent project input field */
+ protected Text parentProjectText;
+
+ /** the "create simple project" checkbox */
+ private Button simpleProject;
+
+ /** the parent object entity */
+ protected Object parentObject;
+
+ /** the parent container */
+ private IContainer parentContainer;
+
+ /** the parent POM file */
+ private IFile pom;
+
+ /** the parent model */
+ private Model parentModel;
+
+ /** working set selector widget */
+ private WorkingSetGroup workingSetGroup;
+
+
+ /** Creates a new page. */
+ public MavenModuleWizardParentPage(ProjectImportConfiguration projectImportConfiguration) {
+ super("MavenModuleWizardParentPage", projectImportConfiguration);
+ setTitle(Messages.getString("wizard.module.page.parent.title")); //$NON-NLS-1$
+ setDescription(Messages.getString("wizard.module.page.parent.description")); //$NON-NLS-1$
+ setPageComplete(false);
+ }
+
+ /** Creates the page controls. */
+ public void createControl(Composite parent) {
+ Composite container = new Composite(parent, SWT.NULL);
+ container.setLayout(new GridLayout(3, false));
+
+ simpleProject = new Button(container, SWT.CHECK);
+ simpleProject.setText(Messages.getString("wizard.project.page.project.simpleProject")); //$NON-NLS-1$
+ simpleProject.setData("name", "simpleProjectButton"); //$NON-NLS-1$ //$NON-NLS-2$
+ simpleProject.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 3, 1));
+ simpleProject.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ validate();
+ }
+ });
+
+ Label nameLabel = new Label(container, SWT.NONE);
+ GridData gd_nameLabel = new GridData();
+ gd_nameLabel.verticalIndent = 10;
+ nameLabel.setLayoutData(gd_nameLabel);
+ nameLabel.setText(Messages.getString("wizard.module.page.parent.moduleName")); //$NON-NLS-1$
+
+ moduleNameCombo = new Combo(container, SWT.BORDER);
+ GridData gd_moduleNameCombo = new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1);
+ gd_moduleNameCombo.verticalIndent = 10;
+ moduleNameCombo.setLayoutData(gd_moduleNameCombo);
+ moduleNameCombo.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ validate();
+ }
+ });
+ addFieldWithHistory("moduleName", moduleNameCombo); //$NON-NLS-1$
+
+ Label parentLabel = new Label(container, SWT.NONE);
+ parentLabel.setText(Messages.getString("wizard.module.page.parent.parentProject")); //$NON-NLS-1$
+
+ parentProjectText = new Text(container, SWT.BORDER);
+ parentProjectText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));
+ parentProjectText.setEditable(false);
+
+ Button browseButton = new Button(container, SWT.NONE);
+ browseButton.setText(Messages.getString("wizard.module.page.parent.browse")); //$NON-NLS-1$
+ browseButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ MavenProjectSelectionDialog dialog = new MavenProjectSelectionDialog(getShell());
+ if(dialog.open() == Window.OK) {
+ setParent(dialog.getFirstResult());
+ validate();
+ }
+ }
+ });
+
+ this.workingSetGroup = new WorkingSetGroup(container, getImportConfiguration(), getShell());
+
+ createAdvancedSettings(container, new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1));
+
+ initialize();
+
+ setControl(container);
+ }
+
+ /** Initializes the GUI components and validates the page. */
+ private void initialize() {
+ loadParent();
+ validate();
+ }
+
+ /** Validates the data entered. */
+ void validate() {
+ String moduleName = moduleNameCombo.getText().trim();
+ if(moduleName.length() == 0) {
+ setErrorMessage(null);
+ setMessage(Messages.getString("wizard.module.page.parent.validator.moduleName")); //$NON-NLS-1$
+ setPageComplete(false);
+ return;
+ }
+
+ // check whether the project name is valid
+ IStatus nameStatus =
+ ResourcesPlugin.getWorkspace().validateName(moduleName, IResource.PROJECT);
+ if(!nameStatus.isOK()) {
+ setErrorMessage(nameStatus.getMessage());
+ setPageComplete(false);
+ return;
+ }
+
+ // check if the given folder already exists
+ if(parentContainer != null && parentContainer.exists(new Path(moduleName))) {
+ setErrorMessage(Messages.getString("wizard.module.page.parent.validator.nameExists")); //$NON-NLS-1$
+ setPageComplete(false);
+ return;
+ }
+
+ if(pom == null) {
+ setErrorMessage(null);
+ setMessage(Messages.getString("wizard.module.page.parent.validator.parentProject")); //$NON-NLS-1$
+ setPageComplete(false);
+ return;
+ }
+ if(!validateParent()){
+ return;
+ }
+ setErrorMessage(null);
+ setMessage(null);
+ setPageComplete(true);
+ }
+
+ /** Assigns a parent object. */
+ public void setParent(Object parent) {
+ parentObject = parent;
+ loadParent();
+ }
+
+ /** Loads the data from the parent object. */
+ protected void loadParent() {
+ if(parentObject == null) {
+ return;
+ }
+
+ int type = SelectionUtil.getElementType(parentObject);
+
+ if(SelectionUtil.POM_FILE == type) {
+ pom = SelectionUtil.getType(parentObject, IFile.class);
+ } else if(SelectionUtil.PROJECT_WITH_NATURE == type) {
+ IProject project = SelectionUtil.getType(parentObject, IProject.class);
+ pom = project.getFile(IMavenConstants.POM_FILE_NAME);
+
+ workingSetGroup.selectWorkingSets(SelectionUtil.getAssignedWorkingSets(project));
+ } else if(parentObject instanceof IContainer) {
+ pom = ((IContainer) parentObject).getFile(new Path(IMavenConstants.POM_FILE_NAME));
+ }
+
+ if(pom != null && pom.exists()) {
+ parentObject = pom;
+ parentContainer = pom.getParent();
+
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ try {
+ parentModel = plugin.getMavenModelManager().readMavenModel(pom);
+ validateParent();
+ parentProjectText.setText(parentModel.getArtifactId());
+ } catch(CoreException e) {
+ MavenLogger.log("Error loading POM: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private boolean validateParent(){
+ if(parentModel != null){
+ if(!"pom".equals(parentModel.getPackaging())){ //$NON-NLS-1$
+ setMessage(null);
+ setErrorMessage(org.eclipse.m2e.core.internal.Messages.MavenModuleWizardParentPage_error);
+ setPageComplete(false);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** Returns "true" if the user chose not to use archetypes. */
+ public boolean isSimpleProject() {
+ return simpleProject.getSelection();
+ }
+
+ /** Skips the archetype selection page if the user chooses a simple project. */
+ public IWizardPage getNextPage() {
+ return getWizard().getPage(
+ isSimpleProject() ? "MavenProjectWizardArtifactPage" : "MavenProjectWizardArchetypePage");
+ }
+
+ /** Returns the module name. */
+ public String getModuleName() {
+ return moduleNameCombo.getText();
+ }
+
+ /** Returns the parent model. */
+ public Model getParentModel() {
+ return parentModel;
+ }
+
+ /** Returns the parent POM file handle. */
+ public IFile getPom() {
+ return pom;
+ }
+
+ /** Returns the parent container. */
+ public IContainer getParentContainer() {
+ return parentContainer;
+ }
+
+ /** Offers a listener hookup to the pages watching the module name field. */
+ public void addModuleNameListener(ModifyListener modifyListener) {
+ moduleNameCombo.addModifyListener(modifyListener);
+ }
+
+ /** Unhooks the listener watching the module name field. */
+ public void removesModuleNameListener(ModifyListener modifyListener) {
+ moduleNameCombo.removeModifyListener(modifyListener);
+ }
+
+ /** Offers a listener hookup to the pages watching the parent name field. */
+ public void addParentProjectListener(ModifyListener modifyListener) {
+ parentProjectText.addModifyListener(modifyListener);
+ }
+
+ /** Unhooks the listener watching the parent name field. */
+ public void removesParentProjectListener(ModifyListener modifyListener) {
+ parentProjectText.removeModifyListener(modifyListener);
+ }
+
+ /** Offers a listener hookup to the pages watching the archetype switch. */
+ public void addArchetypeSelectionListener(SelectionListener selectionListener) {
+ simpleProject.addSelectionListener(selectionListener);
+ }
+
+ /** Removes the listener watching the project name field. */
+ public void removeArchetypeSelectionListener(SelectionListener selectionListener) {
+ simpleProject.removeSelectionListener(selectionListener);
+ }
+
+ /** Cleans up. */
+ public void dispose() {
+ super.dispose();
+ workingSetGroup.dispose();
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenParentComponent.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenParentComponent.java
new file mode 100644
index 00000000..b40aaeac
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenParentComponent.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Parent;
+
+import org.eclipse.m2e.core.core.Messages;
+
+
+/**
+ * Wizard page component showing panel project properties.
+ */
+public class MavenParentComponent extends Composite {
+
+ /** parent artifact id input field */
+ private Combo parentArtifactIdCombo;
+
+ /** parent group id input field */
+ private Combo parentGroupIdCombo;
+
+ /** parent version input field */
+ private Combo parentVersionCombo;
+
+ /** the "clear parent section" button */
+ private Button parentClearButton;
+
+ /** the "browse..." button */
+ private Button parentBrowseButton;
+
+ private Label groupIdLabel;
+
+ private Label artifactIdLabel;
+
+ private Label versionLabel;
+
+ /** Creates a new panel with parent controls. */
+ public MavenParentComponent(Composite parent, int style) {
+ super(parent, SWT.NONE);
+
+ boolean readonly = (style & SWT.READ_ONLY) != 0;
+
+ GridLayout topLayout = new GridLayout();
+ topLayout.marginHeight = 0;
+ topLayout.marginWidth = 0;
+ setLayout(topLayout);
+
+ Group group = new Group(this, SWT.NONE);
+ group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+ group.setText(Messages.getString("wizard.project.page.artifact.parent.title")); //$NON-NLS-1$
+
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.numColumns = 3;
+ group.setLayout(gridLayout);
+
+ groupIdLabel = new Label(group, SWT.NONE);
+ groupIdLabel.setText(Messages.getString("wizard.project.page.artifact.parent.groupId")); //$NON-NLS-1$
+
+ parentGroupIdCombo = new Combo(group, SWT.NONE);
+ parentGroupIdCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ parentGroupIdCombo.setData("name", "parentGroupIdCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+ parentGroupIdCombo.setEnabled(!readonly);
+
+ artifactIdLabel = new Label(group, SWT.NONE);
+ artifactIdLabel.setText(Messages.getString("wizard.project.page.artifact.parent.artifactId")); //$NON-NLS-1$
+
+ parentArtifactIdCombo = new Combo(group, SWT.NONE);
+ parentArtifactIdCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ parentArtifactIdCombo.setData("name", "parentArtifactIdCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+ parentArtifactIdCombo.setEnabled(!readonly);
+
+ versionLabel = new Label(group, SWT.NONE);
+ versionLabel.setText(Messages.getString("wizard.project.page.artifact.parent.version")); //$NON-NLS-1$
+
+ parentVersionCombo = new Combo(group, SWT.NONE);
+ GridData gd_versionCombo = new GridData(SWT.LEFT, SWT.CENTER, true, false);
+ gd_versionCombo.widthHint = 150;
+ parentVersionCombo.setLayoutData(gd_versionCombo);
+ parentVersionCombo.setEnabled(!readonly);
+ parentVersionCombo.setData("name", "parentVersionCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ if(!readonly) {
+ Composite buttonPanel = new Composite(group, SWT.NONE);
+ RowLayout rowLayout = new RowLayout();
+ rowLayout.pack = false;
+ rowLayout.marginTop = 0;
+ rowLayout.marginRight = 0;
+ rowLayout.marginLeft = 0;
+ rowLayout.marginBottom = 0;
+ buttonPanel.setLayout(rowLayout);
+ buttonPanel.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+
+ parentBrowseButton = new Button(buttonPanel, SWT.NONE);
+ parentBrowseButton.setText(Messages.getString("wizard.project.page.artifact.parent.browse")); //$NON-NLS-1$
+ parentBrowseButton.setData("name", "parentBrowseButton"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ parentClearButton = new Button(buttonPanel, SWT.NONE);
+ parentClearButton.setText(Messages.getString("wizard.project.page.artifact.parent.clear")); //$NON-NLS-1$
+ parentClearButton.setData("name", "parentClearButton"); //$NON-NLS-1$ //$NON-NLS-2$
+ parentClearButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ setValues("", "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ });
+ }
+ }
+
+ public Combo getGroupIdCombo() {
+ return parentGroupIdCombo;
+ }
+
+ public Combo getArtifactIdCombo() {
+ return this.parentArtifactIdCombo;
+ }
+
+ public Combo getVersionCombo() {
+ return this.parentVersionCombo;
+ }
+
+ public void setWidthGroup(WidthGroup widthGroup) {
+ widthGroup.addControl(this.groupIdLabel);
+ widthGroup.addControl(this.artifactIdLabel);
+ widthGroup.addControl(this.versionLabel);
+ }
+
+ /** Adds modify listener to the input controls. */
+ public void addModifyListener(ModifyListener listener) {
+ parentArtifactIdCombo.addModifyListener(listener);
+ parentGroupIdCombo.addModifyListener(listener);
+ parentVersionCombo.addModifyListener(listener);
+ }
+
+ /** Removes the listener from the input controls. */
+ public void removeModifyListener(ModifyListener listener) {
+ parentArtifactIdCombo.removeModifyListener(listener);
+ parentGroupIdCombo.removeModifyListener(listener);
+ parentVersionCombo.removeModifyListener(listener);
+ }
+
+ /** Adds selection listener to the "browse" button. */
+ public void addBrowseButtonListener(SelectionListener listener) {
+ if(parentBrowseButton != null) {
+ parentBrowseButton.addSelectionListener(listener);
+ }
+ }
+
+ /** Removes the selection listener from the "browse" button. */
+ public void removeBrowseButtonListener(SelectionListener listener) {
+ if(parentBrowseButton != null) {
+ parentBrowseButton.removeSelectionListener(listener);
+ }
+ }
+
+ /** Enables the "clear" button. */
+ public void setClearButtonEnabled(boolean enabled) {
+ if(parentClearButton != null) {
+ parentClearButton.setEnabled(enabled);
+ }
+ }
+
+ /** Sets the parent group values. */
+ public void setValues(String groupId, String artifactId, String version) {
+ parentGroupIdCombo.setText(groupId==null ? "" : groupId); //$NON-NLS-1$
+ parentArtifactIdCombo.setText(artifactId==null ? "" : artifactId); //$NON-NLS-1$
+ parentVersionCombo.setText(version==null ? "" : version); //$NON-NLS-1$
+ }
+
+ /** Updates a Maven model. */
+ public void updateModel(Model model) {
+ String groupId = parentGroupIdCombo.getText().trim();
+ if(groupId.length() > 0) {
+ Parent parent = new Parent();
+ parent.setGroupId(groupId);
+ parent.setArtifactId(parentArtifactIdCombo.getText().trim());
+ parent.setVersion(parentVersionCombo.getText().trim());
+ model.setParent(parent);
+ }
+ }
+
+ /**
+ * Validates the inputs to make sure all three fields are present in the same time, or none at all.
+ */
+ public boolean validate() {
+ int parentCheck = 0;
+ if(parentGroupIdCombo.getText().trim().length() > 0) {
+ parentCheck++ ;
+ }
+ if(parentArtifactIdCombo.getText().trim().length() > 0) {
+ parentCheck++ ;
+ }
+ if(parentVersionCombo.getText().trim().length() > 0) {
+ parentCheck++ ;
+ }
+
+ setClearButtonEnabled(parentCheck > 0);
+
+ return parentCheck == 0 || parentCheck == 3;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomSelectionComponent.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomSelectionComponent.java
new file mode 100644
index 00000000..6c708de5
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomSelectionComponent.java
@@ -0,0 +1,580 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.ibm.icu.text.DateFormat;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+import org.apache.lucene.search.BooleanQuery;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexManager;
+import org.eclipse.m2e.core.index.IndexedArtifact;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.index.UserInputSearchExpression;
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * MavenPomSelectionComposite
+ *
+ * @author Eugene Kuleshov
+ */
+public class MavenPomSelectionComponent extends Composite {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Widget#dispose()
+ */
+ public void dispose() {
+ if(searchJob != null) {
+ searchJob.cancel();
+ }
+ super.dispose();
+ }
+
+ Text searchText = null;
+
+ TreeViewer searchResultViewer = null;
+
+ Button javadocCheckBox;
+
+ Button sourcesCheckBox;
+
+ Button testCheckBox;
+
+ /**
+ * One of {@link IIndex#SEARCH_ARTIFACT}, {@link IIndex#SEARCH_CLASS_NAME},
+ */
+ String queryType;
+
+ SearchJob searchJob;
+
+ private IStatus status;
+
+ private ISelectionChangedListener selectionListener;
+
+ public static final String P_SEARCH_INCLUDE_JAVADOC = "searchIncludesJavadoc"; //$NON-NLS-1$
+
+ public static final String P_SEARCH_INCLUDE_SOURCES = "searchIncludesSources"; //$NON-NLS-1$
+
+ public static final String P_SEARCH_INCLUDE_TESTS = "searchIncludesTests"; //$NON-NLS-1$
+
+ private static final long SHORT_DELAY = 150L;
+
+ private static final long LONG_DELAY = 500L;
+
+ final HashSet<String> artifactKeys = new HashSet<String>();
+ final HashSet<String> managedKeys = new HashSet<String>();
+
+ public MavenPomSelectionComponent(Composite parent, int style) {
+ super(parent, style);
+ createSearchComposite();
+ }
+
+ private void createSearchComposite() {
+ GridLayout gridLayout = new GridLayout(2, false);
+ gridLayout.marginWidth = 0;
+ gridLayout.marginHeight = 0;
+ setLayout(gridLayout);
+
+ Label searchTextlabel = new Label(this, SWT.NONE);
+ searchTextlabel.setText(Messages.MavenPomSelectionComponent_search_title);
+ searchTextlabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
+
+ searchText = new Text(this, SWT.BORDER | SWT.SEARCH);
+ searchText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1));
+ searchText.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent e) {
+ if(e.keyCode == SWT.ARROW_DOWN) {
+ searchResultViewer.getTree().setFocus();
+ selectFirstElementInTheArtifactTreeIfNoSelectionHasBeenMade();
+ }
+ }
+ });
+
+ searchText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ scheduleSearch(searchText.getText(), true);
+ }
+ });
+
+ Label searchResultsLabel = new Label(this, SWT.NONE);
+ searchResultsLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1));
+ searchResultsLabel.setText(Messages.MavenPomSelectionComponent_lblResults);
+
+ Tree tree = new Tree(this, SWT.BORDER | SWT.SINGLE);
+ tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+ tree.setData("name", "searchResultTree"); //$NON-NLS-1$ //$NON-NLS-2$
+ tree.addFocusListener(new FocusListener() {
+
+ public void focusGained(FocusEvent e) {
+ selectFirstElementInTheArtifactTreeIfNoSelectionHasBeenMade();
+ }
+
+ public void focusLost(FocusEvent e) {
+
+ }
+ });
+
+ searchResultViewer = new TreeViewer(tree);
+ }
+
+ void selectFirstElementInTheArtifactTreeIfNoSelectionHasBeenMade() {
+ //
+ // If we have started a new search when focus is passed to the tree viewer we will automatically select
+ // the first element if no element has been selected from a previous expedition into the tree viewer.
+ //
+ if(searchResultViewer.getTree().getItemCount() > 0 && searchResultViewer.getSelection().isEmpty()) {
+ Object artifact = searchResultViewer.getTree().getTopItem().getData();
+ searchResultViewer.setSelection(new StructuredSelection(artifact), true);
+ }
+ }
+
+ protected boolean showClassifiers() {
+ return (queryType != null && IIndex.SEARCH_ARTIFACT.equals(queryType));
+ }
+
+ private void setupButton(final Button button, String label, final String prefName, int horizontalIndent) {
+ button.setText(label);
+ GridData gd = new GridData(SWT.LEFT, SWT.TOP, false, false);
+ gd.horizontalIndent = horizontalIndent;
+ button.setLayoutData(gd);
+ boolean check = MavenPlugin.getDefault().getPreferenceStore().getBoolean(prefName);
+ button.setSelection(check);
+ button.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ boolean checked = button.getSelection();
+ MavenPlugin.getDefault().getPreferenceStore().setValue(prefName, checked);
+ scheduleSearch(searchText.getText(), false);
+ }
+ });
+ }
+
+ public void init(String queryText, String queryType, Set<ArtifactKey> artifacts, Set<ArtifactKey> managed) {
+ this.queryType = queryType;
+
+ if(queryText != null) {
+ searchText.setText(queryText);
+ }
+
+ if(artifacts != null) {
+ for(ArtifactKey a : artifacts) {
+ artifactKeys.add(a.getGroupId() + ":" + a.getArtifactId()); //$NON-NLS-1$
+ artifactKeys.add(a.getGroupId() + ":" + a.getArtifactId() + ":" + a.getVersion()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ if (managed != null) {
+ for (ArtifactKey a : managed) {
+ managedKeys.add(a.getGroupId() + ":" + a.getArtifactId()); //$NON-NLS-1$
+ managedKeys.add(a.getGroupId() + ":" + a.getArtifactId() + ":" + a.getVersion()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ searchResultViewer.setContentProvider(new SearchResultContentProvider());
+ searchResultViewer.setLabelProvider(new DelegatingStyledCellLabelProvider(new SearchResultLabelProvider(artifactKeys, managedKeys, queryType)));
+ searchResultViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+ if(!selection.isEmpty()) {
+ if(selection.size() == 1) {
+ IndexedArtifactFile f = getSelectedIndexedArtifactFile(selection.getFirstElement());
+ // int severity = artifactKeys.contains(f.group + ":" + f.artifact) ? IStatus.ERROR : IStatus.OK;
+ int severity = IStatus.OK;
+ String date = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT).format(f.date);
+ setStatus(
+ severity,
+ NLS.bind(Messages.MavenPomSelectionComponent_detail1, f.fname,
+ (f.size != -1 ? NLS.bind(Messages.MavenPomSelectionComponent_details2, date, f.size) : date)));
+ } else {
+ setStatus(IStatus.OK, NLS.bind(Messages.MavenPomSelectionComponent_selected, selection.size()));
+ }
+ } else {
+ setStatus(IStatus.ERROR, Messages.MavenPomSelectionComponent_nosel);
+ }
+ }
+ });
+ setupClassifiers();
+ setStatus(IStatus.ERROR, ""); //$NON-NLS-1$
+ scheduleSearch(queryText, false);
+ }
+
+ protected void setupClassifiers() {
+ if(showClassifiers()) {
+ Composite includesComp = new Composite(this, SWT.NONE);
+ includesComp.setLayout(new GridLayout(3, true));
+ GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, false);
+ includesComp.setLayoutData(gd);
+
+ javadocCheckBox = new Button(includesComp, SWT.CHECK);
+ setupButton(javadocCheckBox, Messages.MavenPomSelectionComponent_btnJavadoc, P_SEARCH_INCLUDE_JAVADOC, 0);
+
+ sourcesCheckBox = new Button(includesComp, SWT.CHECK);
+ setupButton(sourcesCheckBox, Messages.MavenPomSelectionComponent_btnSource, P_SEARCH_INCLUDE_SOURCES, 10);
+
+ testCheckBox = new Button(includesComp, SWT.CHECK);
+ setupButton(testCheckBox, Messages.MavenPomSelectionComponent_btnTests, P_SEARCH_INCLUDE_TESTS, 10);
+ }
+ }
+
+ public IStatus getStatus() {
+ return this.status;
+ }
+
+ public void addDoubleClickListener(IDoubleClickListener listener) {
+ searchResultViewer.addDoubleClickListener(listener);
+ }
+
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ this.selectionListener = listener;
+ }
+
+ void setStatus(int severity, String message) {
+ this.status = new Status(severity, IMavenConstants.PLUGIN_ID, 0, message, null);
+ if(selectionListener != null) {
+ selectionListener.selectionChanged(new SelectionChangedEvent(searchResultViewer, searchResultViewer
+ .getSelection()));
+ }
+ }
+
+ public IndexedArtifact getIndexedArtifact() {
+ IStructuredSelection selection = (IStructuredSelection) searchResultViewer.getSelection();
+ Object element = selection.getFirstElement();
+ if(element instanceof IndexedArtifact) {
+ return (IndexedArtifact) element;
+ }
+ TreeItem[] treeItems = searchResultViewer.getTree().getSelection();
+ if(treeItems.length == 0) {
+ return null;
+ }
+ return (IndexedArtifact) treeItems[0].getParentItem().getData();
+ }
+
+ public IndexedArtifactFile getIndexedArtifactFile() {
+ IStructuredSelection selection = (IStructuredSelection) searchResultViewer.getSelection();
+ return getSelectedIndexedArtifactFile(selection.getFirstElement());
+ }
+
+ IndexedArtifactFile getSelectedIndexedArtifactFile(Object element) {
+ if(element instanceof IndexedArtifact) {
+ //the idea here is that if we have a managed version for something, then the IndexedArtifact shall
+ //represent that value..
+ IndexedArtifact ia = (IndexedArtifact)element;
+ if (managedKeys.contains(getKey(ia))) {
+ for (IndexedArtifactFile file : ia.getFiles()) {
+ if (managedKeys.contains(getKey(file))) {
+ return file;
+ }
+ }
+ }
+ return ia.getFiles().iterator().next();
+ }
+ return (IndexedArtifactFile) element;
+ }
+
+ void scheduleSearch(String query, boolean delay) {
+ if(query != null && query.length() > 2) {
+ if(searchJob == null) {
+ IndexManager indexManager = MavenPlugin.getDefault().getIndexManager();
+ searchJob = new SearchJob(queryType, indexManager);
+ } else {
+ if(!searchJob.cancel()) {
+ //for already running ones, just create new instance so that the previous one can piecefully die
+ //without preventing the new one from completing first
+ IndexManager indexManager = MavenPlugin.getDefault().getIndexManager();
+ searchJob = new SearchJob(queryType, indexManager);
+ }
+ }
+ searchJob.setQuery(query.toLowerCase());
+ searchJob.schedule(delay ? LONG_DELAY : SHORT_DELAY);
+ } else {
+ if(searchJob != null) {
+ searchJob.cancel();
+ }
+ }
+ }
+
+ static String getKey(IndexedArtifactFile file) {
+ return file.group + ":" + file.artifact + ":" + file.version; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ static String getKey(IndexedArtifact art) {
+ return art.getGroupId() + ":" + art.getArtifactId(); //$NON-NLS-1$
+ }
+
+
+ /**
+ * Search Job
+ */
+ private class SearchJob extends Job {
+
+ private IndexManager indexManager;
+
+ private String query;
+
+ private String field;
+
+ private volatile boolean stop = false;
+
+ public SearchJob(String field, IndexManager indexManager) {
+ super(Messages.MavenPomSelectionComponent_searchJob);
+ this.field = field;
+ this.indexManager = indexManager;
+ }
+
+ public void setQuery(String query) {
+ this.query = query;
+ }
+
+ public boolean shouldRun() {
+ stop = false;
+ return super.shouldRun();
+ }
+
+ public int getClassifier() {
+ int classifier = IIndex.SEARCH_JARS;
+ if(MavenPlugin.getDefault().getPreferenceStore().getBoolean(P_SEARCH_INCLUDE_JAVADOC)) {
+ classifier = classifier + IIndex.SEARCH_JAVADOCS;
+ }
+ if(MavenPlugin.getDefault().getPreferenceStore().getBoolean(P_SEARCH_INCLUDE_SOURCES)) {
+ classifier = classifier + IIndex.SEARCH_SOURCES;
+ }
+ if(MavenPlugin.getDefault().getPreferenceStore().getBoolean(P_SEARCH_INCLUDE_TESTS)) {
+ classifier = classifier + IIndex.SEARCH_TESTS;
+ }
+ return classifier;
+ }
+
+ protected IStatus run(IProgressMonitor monitor) {
+ int classifier = showClassifiers() ? getClassifier() : IIndex.SEARCH_ALL;
+ if(searchResultViewer == null || searchResultViewer.getControl() == null
+ || searchResultViewer.getControl().isDisposed()) {
+ return Status.CANCEL_STATUS;
+ }
+ if(query != null) {
+ String activeQuery = query;
+ try {
+ setResult(IStatus.OK, NLS.bind(Messages.MavenPomSelectionComponent_searching, activeQuery.toLowerCase()),
+ null);
+
+ // TODO: cstamas identified this as "user input", true?
+ Map<String, IndexedArtifact> res = indexManager.getAllIndexes().search( new UserInputSearchExpression(activeQuery), field, classifier);
+ setResult(IStatus.OK, NLS.bind(Messages.MavenPomSelectionComponent_results, activeQuery, res.size()), res);
+ } catch(BooleanQuery.TooManyClauses ex) {
+ setResult(IStatus.ERROR, Messages.MavenPomSelectionComponent_toomany,
+ Collections.<String, IndexedArtifact> emptyMap());
+ } catch(final RuntimeException ex) {
+ setResult(IStatus.ERROR, NLS.bind(Messages.MavenPomSelectionComponent_error, ex.toString()),
+ Collections.<String, IndexedArtifact> emptyMap());
+ } catch(final Exception ex) {
+ setResult(IStatus.ERROR, NLS.bind(Messages.MavenPomSelectionComponent_error, ex.getMessage()),
+ Collections.<String, IndexedArtifact> emptyMap());
+ }
+ }
+ return Status.OK_STATUS;
+ }
+
+ protected void canceling() {
+ stop = true;
+ }
+
+ private void setResult(final int severity, final String message, final Map<String, IndexedArtifact> result) {
+ if(stop)
+ return;
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ setStatus(severity, message);
+ if(result != null) {
+ if(!searchResultViewer.getControl().isDisposed()) {
+ searchResultViewer.setInput(result);
+ }
+ }
+ }
+ });
+ }
+ }
+
+ public static class SearchResultLabelProvider extends LabelProvider implements IColorProvider, DelegatingStyledCellLabelProvider.IStyledLabelProvider {
+ private final Set<String> artifactKeys;
+
+ private final String queryType;
+ private final Set<String> managedKeys;
+
+ /**
+ * both managedkeys and artifctkeys are supposed to hold both gr:art:ver combos and gr:art combos
+ * @param artifactKeys
+ * @param managedKeys
+ * @param queryType
+ */
+ public SearchResultLabelProvider(Set<String> artifactKeys, Set<String> managedKeys, String queryType) {
+ this.artifactKeys = artifactKeys;
+ this.queryType = queryType;
+ this.managedKeys = managedKeys;
+ }
+
+ public String getText(Object element) {
+ return super.getText(element);
+ }
+
+ protected String getRepoDisplayName(String repo) {
+ return repo;
+ }
+
+ public Color getForeground(Object element) {
+ if(element instanceof IndexedArtifactFile) {
+ IndexedArtifactFile f = (IndexedArtifactFile) element;
+ if(artifactKeys.contains(getKey(f))) {
+ return Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY);
+ }
+ } else if(element instanceof IndexedArtifact) {
+ IndexedArtifact i = (IndexedArtifact) element;
+ if(artifactKeys.contains(getKey(i))) {
+ return Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY);
+ }
+ }
+ return null;
+ }
+
+ public Color getBackground(Object element) {
+ return null;
+ }
+
+ public Image getImage(Object element) {
+ if(element instanceof IndexedArtifactFile) {
+ IndexedArtifactFile f = (IndexedArtifactFile) element;
+ if (managedKeys.contains(getKey(f))) {
+ return MavenImages.getOverlayImage(f.sourcesExists==IIndex.PRESENT ? MavenImages.PATH_VERSION_SRC : MavenImages.PATH_VERSION,
+ MavenImages.PATH_LOCK, IDecoration.BOTTOM_LEFT);
+ }
+
+ if(f.sourcesExists==IIndex.PRESENT) {
+ return MavenImages.IMG_VERSION_SRC;
+ }
+ return MavenImages.IMG_VERSION;
+ } else if(element instanceof IndexedArtifact) {
+ IndexedArtifact i = (IndexedArtifact) element;
+ if (managedKeys.contains(getKey(i))) {
+ return MavenImages.getOverlayImage(MavenImages.PATH_JAR, MavenImages.PATH_LOCK, IDecoration.BOTTOM_LEFT);
+ }
+ return MavenImages.IMG_JAR;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider#getStyledText(java.lang.Object)
+ */
+ public StyledString getStyledText(Object element) {
+ if(element instanceof IndexedArtifact) {
+ IndexedArtifact a = (IndexedArtifact) element;
+ String name = (a.getClassname() == null ? "" : a.getClassname() + " " + a.getPackageName() + " ") + a.getGroupId() + " " + a.getArtifactId(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ StyledString ss = new StyledString();
+ ss.append(name);
+ if (managedKeys.contains(getKey(a))) {
+ ss.append(Messages.MavenPomSelectionComponent_managed_decoration, StyledString.DECORATIONS_STYLER);
+ }
+ return ss;
+ } else if(element instanceof IndexedArtifactFile) {
+ IndexedArtifactFile f = (IndexedArtifactFile) element;
+ StyledString ss = new StyledString();
+ String name = f.version + " [" + (f.type == null ? "jar" : f.type) + (f.classifier != null ? ", " + f.classifier : "") + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ ss.append(name);
+ if (managedKeys.contains(getKey(f))) {
+ ss.append(Messages.MavenPomSelectionComponent_managed_decoration, StyledString.DECORATIONS_STYLER);
+ }
+ return ss;
+ }
+ return new StyledString();
+ }
+
+ }
+
+ public static class SearchResultContentProvider implements ITreeContentProvider {
+ private static Object[] EMPTY = new Object[0];
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ public Object[] getElements(Object inputElement) {
+ if(inputElement instanceof Map) {
+ return ((Map<?, ?>) inputElement).values().toArray();
+ }
+ return EMPTY;
+ }
+
+ public Object[] getChildren(Object parentElement) {
+ if(parentElement instanceof IndexedArtifact) {
+ IndexedArtifact a = (IndexedArtifact) parentElement;
+ return a.getFiles().toArray();
+ }
+ return EMPTY;
+ }
+
+ public boolean hasChildren(Object element) {
+ return element instanceof IndexedArtifact;
+ }
+
+ public Object getParent(Object element) {
+ return null;
+ }
+
+ public void dispose() {
+
+ }
+
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomWizard.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomWizard.java
new file mode 100644
index 00000000..b3c5b2cc
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomWizard.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.INewWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.MavenModelManager;
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * New POM wizard
+ */
+public class MavenPomWizard extends Wizard implements INewWizard {
+ private MavenPomWizardPage artifactPage;
+
+ private MavenDependenciesWizardPage dependenciesPage;
+
+ private ISelection selection;
+
+ /**
+ * Constructor for MavenPomWizard.
+ */
+ public MavenPomWizard() {
+ super();
+ setNeedsProgressMonitor(true);
+ setWindowTitle(Messages.MavenPomWizard_title);
+ }
+
+ /**
+ * Adding the page to the wizard.
+ */
+
+ public void addPages() {
+ artifactPage = new MavenPomWizardPage(selection);
+ dependenciesPage = new MavenDependenciesWizardPage();
+ dependenciesPage.setDependencies(new Dependency[0]);
+
+ addPage(artifactPage);
+ addPage(dependenciesPage);
+ }
+
+ /**
+ * This method is called when 'Finish' button is pressed in the wizard. We will create an operation and run it using
+ * wizard as execution context.
+ */
+ public boolean performFinish() {
+ final String projectName = artifactPage.getProject();
+ final Model model = artifactPage.getModel();
+ @SuppressWarnings("unchecked")
+ List<Dependency> modelDependencies = model.getDependencies();
+ modelDependencies.addAll(Arrays.asList(dependenciesPage.getDependencies()));
+
+ IRunnableWithProgress op = new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor) throws InvocationTargetException {
+ monitor.beginTask(Messages.MavenPomWizard_task, 1);
+ try {
+ doFinish(projectName, model, monitor);
+ monitor.worked(1);
+ } catch(CoreException e) {
+ throw new InvocationTargetException(e);
+ } finally {
+ monitor.done();
+ }
+ }
+ };
+
+ try {
+ getContainer().run(true, false, op);
+ } catch(InterruptedException e) {
+ return false;
+ } catch(InvocationTargetException e) {
+ Throwable realException = e.getTargetException();
+ MessageDialog.openError(getShell(), Messages.MavenPomWizard_error_title, realException.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * The worker method. It will find the container, create the file if missing or just replace its contents, and open
+ * the editor on the newly created file.
+ */
+ void doFinish(String projectName, final Model model, IProgressMonitor monitor) throws CoreException {
+ // monitor.beginTask("Creating " + fileName, 2);
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IResource resource = root.findMember(new Path(projectName));
+ if(!resource.exists() || (resource.getType() & IResource.FOLDER | IResource.PROJECT) == 0) {
+ // TODO show warning popup
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1,
+ NLS.bind(Messages.MavenPomWizard_status_not_exists, projectName), null));
+ }
+
+ IContainer container = (IContainer) resource;
+ final IFile file = container.getFile(new Path(IMavenConstants.POM_FILE_NAME));
+ if(file.exists()) {
+ // TODO show warning popup
+ throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenPomWizard_error_exists, null));
+ }
+
+ final File pom = file.getLocation().toFile();
+
+ try {
+ MavenModelManager modelManager = MavenPlugin.getDefault().getMavenModelManager();
+ modelManager.createMavenModel(file, model);
+
+ getShell().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ try {
+ IDE.openEditor(page, file, true);
+ } catch(PartInitException e) {
+ }
+ }
+ });
+
+ } catch(Exception ex) {
+ MavenLogger.log("Unable to create POM " + pom + "; " + ex.getMessage(), ex);
+
+ }
+ }
+
+ /**
+ * We will accept the selection in the workbench to see if we can initialize from it.
+ *
+ * @see IWorkbenchWizard#init(IWorkbench, IStructuredSelection)
+ */
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ this.selection = selection;
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomWizardPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomWizardPage.java
new file mode 100644
index 00000000..b2b62645
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenPomWizardPage.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.ContainerSelectionDialog;
+
+import org.apache.maven.model.Model;
+
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * Wizard page used to specify basic POM parameters
+ */
+public class MavenPomWizardPage extends AbstractMavenWizardPage {
+ private Text projectText;
+
+ private ISelection selection;
+
+ private MavenArtifactComponent pomComponent;
+
+ public MavenPomWizardPage(ISelection selection) {
+ super("wizardPage"); //$NON-NLS-1$
+ setTitle(Messages.MavenPomWizardPage_title);
+ setDescription(Messages.MavenPomWizardPage_desc);
+ this.selection = selection;
+ }
+
+ public void createControl(Composite parent) {
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 3;
+ layout.makeColumnsEqualWidth = false;
+
+ Composite container = new Composite(parent, SWT.NULL);
+ container.setLayout(layout);
+
+ ModifyListener modifyingListener = new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ dialogChanged();
+ }
+ };
+
+ Label label = new Label(container, SWT.NULL);
+ label.setText(Messages.MavenPomWizardPage_lblProject);
+
+ projectText = new Text(container, SWT.BORDER | SWT.SINGLE);
+ projectText.setEditable(false);
+ projectText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ projectText.addModifyListener(modifyingListener);
+
+ Button button = new Button(container, SWT.PUSH);
+ final GridData gridData_2 = new GridData();
+ button.setLayoutData(gridData_2);
+ button.setText(Messages.MavenPomWizardPage_btnBrowse);
+ button.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ handleBrowse();
+ }
+ });
+
+ pomComponent = new MavenArtifactComponent(container, SWT.NONE);
+ pomComponent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
+ pomComponent.setModifyingListener(modifyingListener);
+ addFieldWithHistory("groupId", pomComponent.getGroupIdCombo()); //$NON-NLS-1$
+ addFieldWithHistory("artifactId", pomComponent.getArtifactIdCombo()); //$NON-NLS-1$
+ addFieldWithHistory("version", pomComponent.getVersionCombo()); //$NON-NLS-1$
+ addFieldWithHistory("name", pomComponent.getNameCombo()); //$NON-NLS-1$
+
+ initialize();
+ dialogChanged();
+ setControl(container);
+ }
+
+ /**
+ * Tests if the current workbench selection is a suitable container to use.
+ */
+ private void initialize() {
+ if(selection != null && !selection.isEmpty() && selection instanceof IStructuredSelection) {
+ IStructuredSelection ssel = (IStructuredSelection) selection;
+ if(ssel.size() > 1) {
+ return;
+ }
+ Object obj = ssel.getFirstElement();
+ if(obj instanceof IResource) {
+ IContainer container;
+ if(obj instanceof IContainer) {
+ container = (IContainer) obj;
+ } else {
+ container = ((IResource) obj).getParent();
+ }
+ projectText.setText(container.getFullPath().toString());
+ pomComponent.setArtifactId(container.getName());
+ pomComponent.setGroupId(container.getName());
+ }
+ }
+
+ pomComponent.setVersion(MavenArtifactComponent.DEFAULT_VERSION);
+ pomComponent.setPackaging(MavenArtifactComponent.DEFAULT_PACKAGING);
+ }
+
+ /**
+ * Uses the standard container selection dialog to choose the new value for the container field.
+ */
+ void handleBrowse() {
+ ContainerSelectionDialog dialog = new ContainerSelectionDialog(getShell(),
+ ResourcesPlugin.getWorkspace().getRoot(), false, Messages.MavenPomWizardPage_dialog_title);
+ dialog.showClosedProjects(false);
+ if(dialog.open() == Window.OK) {
+ Object[] result = dialog.getResult();
+ if(result.length == 1) {
+ projectText.setText(((Path) result[0]).toString());
+ }
+ }
+
+// IJavaModel javaModel = JavaCore.create();
+//
+// IJavaProject[] projects;
+// try {
+// projects = javaModel.getJavaProjects();
+// } catch(JavaModelException e) {
+// MavenLogger.log(e);
+// projects = new IJavaProject[0];
+// }
+//
+// ILabelProvider labelProvider = new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT);
+// ElementListSelectionDialog dialog = new ElementListSelectionDialog(getShell(), labelProvider);
+// dialog.setTitle("Select Project");
+// dialog.setMessage("Choose project where POM will be created");
+// dialog.setElements(projects);
+//
+// String projectName = getProject();
+// if(projectName != null && projectName.length() > 0) {
+// IJavaProject javaProject = javaModel.getJavaProject(projectName);
+// if(javaProject != null) {
+// dialog.setInitialSelections(new Object[] {javaProject});
+// }
+// }
+//
+// if(dialog.open() == Window.OK) {
+// projectText.setText(((IJavaProject) dialog.getFirstResult()).getProject().getFullPath().toString());
+// }
+ }
+
+ /**
+ * Ensures that both text fields are set.
+ */
+ void dialogChanged() {
+ IResource container = ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(getProject()));
+
+ if(getProject().length() == 0) {
+ updateStatus(Messages.MavenPomWizardPage_error_folder);
+ return;
+ }
+ if(container == null || (container.getType() & IResource.FOLDER | IResource.PROJECT) == 0) {
+ updateStatus(Messages.MavenPomWizardPage_error_folder2);
+ return;
+ }
+ if(!container.isAccessible()) {
+ updateStatus(Messages.MavenPomWizardPage_error_folder_write);
+ return;
+ }
+
+ // TODO
+ if(pomComponent.getGroupId().length() == 0) {
+ updateStatus(Messages.MavenPomWizardPage_error_grid);
+ }
+
+ if(pomComponent.getArtifactId().length() == 0) {
+ updateStatus(Messages.MavenPomWizardPage_error_artid);
+ }
+
+ if(pomComponent.getVersion().length() == 0) {
+ updateStatus(Messages.MavenPomWizardPage_error_version);
+ }
+
+ if(pomComponent.getPackaging().length() == 0) {
+ updateStatus(Messages.MavenPomWizardPage_error_pack);
+ }
+
+ updateStatus(null);
+ }
+
+ private void updateStatus(String message) {
+ setErrorMessage(message);
+ setPageComplete(message == null);
+ }
+
+ public String getProject() {
+ return projectText.getText();
+ }
+
+ public Model getModel() {
+ return pomComponent.getModel();
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectCheckoutJob.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectCheckoutJob.java
new file mode 100644
index 00000000..f894e0f6
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectCheckoutJob.java
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.resources.WorkspaceJob;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.NewProjectAction;
+import org.eclipse.ui.progress.IProgressConstants;
+
+import org.codehaus.plexus.util.DirectoryScanner;
+import org.codehaus.plexus.util.FileUtils;
+
+import org.apache.maven.model.Model;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.actions.OpenMavenConsoleAction;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.MavenModelManager;
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.LocalProjectScanner;
+import org.eclipse.m2e.core.project.MavenProjectInfo;
+import org.eclipse.m2e.core.project.MavenProjectScmInfo;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+import org.eclipse.m2e.core.scm.MavenCheckoutOperation;
+
+
+/**
+ * Maven project checkout Job
+ *
+ * @author Eugene Kuleshov
+ */
+public abstract class MavenProjectCheckoutJob extends WorkspaceJob {
+
+ final ProjectImportConfiguration configuration;
+
+ boolean checkoutAllProjects;
+
+ Collection<MavenProjectInfo> projects;
+
+ File location;
+
+ List<String> collectedLocations = new ArrayList<String>();
+
+ public MavenProjectCheckoutJob(ProjectImportConfiguration importConfiguration, boolean checkoutAllProjects) {
+ super(Messages.MavenProjectCheckoutJob_title);
+ this.configuration = importConfiguration;
+ this.checkoutAllProjects = checkoutAllProjects;
+
+ setProperty(IProgressConstants.ACTION_PROPERTY, new OpenMavenConsoleAction());
+ addJobChangeListener(new CheckoutJobChangeListener());
+ }
+
+ public void setLocation(File location) {
+ this.location = location;
+ }
+
+ protected abstract Collection<MavenProjectScmInfo> getProjects(IProgressMonitor monitor) throws InterruptedException;
+
+
+ // WorkspaceJob
+
+ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
+ try {
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ MavenConsole console = plugin.getConsole();
+
+ MavenCheckoutOperation operation = new MavenCheckoutOperation(location, getProjects(monitor), console);
+ operation.run(monitor);
+ collectedLocations.addAll(operation.getLocations());
+
+ IWorkspaceRoot workspace = ResourcesPlugin.getWorkspace().getRoot();
+
+ MavenModelManager modelManager = plugin.getMavenModelManager();
+
+ LocalProjectScanner scanner = new LocalProjectScanner(workspace.getLocation().toFile(), operation.getLocations(),
+ true, modelManager, console);
+ scanner.run(monitor);
+
+ this.projects = plugin.getProjectConfigurationManager().collectProjects(scanner.getProjects());
+
+ if(checkoutAllProjects) {
+ // check if there any project name conflicts
+ for(MavenProjectInfo projectInfo : projects) {
+ Model model = projectInfo.getModel();
+ if(model == null) {
+ model = modelManager.readMavenModel(projectInfo.getPomFile());
+ projectInfo.setModel(model);
+ }
+
+ String projectName = configuration.getProjectName(model);
+ IProject project = workspace.getProject(projectName);
+ if(project.exists()) {
+ checkoutAllProjects = false;
+ break;
+ }
+ }
+ }
+
+ return Status.OK_STATUS;
+
+ } catch(InterruptedException ex) {
+ return Status.CANCEL_STATUS;
+ }
+ }
+
+ /**
+ * Checkout job listener
+ */
+ final class CheckoutJobChangeListener extends JobChangeAdapter {
+
+ public void done(IJobChangeEvent event) {
+ IStatus result = event.getResult();
+ if(result.getSeverity() == IStatus.CANCEL) {
+ return;
+ } else if(!result.isOK()) {
+ // XXX report errors
+ return;
+ }
+
+ if(projects.isEmpty()) {
+ MavenPlugin.getDefault().getConsole().logMessage("No Maven projects to import");
+
+ if(collectedLocations.size()==1) {
+ final String location = collectedLocations.get(0);
+
+ DirectoryScanner projectScanner = new DirectoryScanner();
+ projectScanner.setBasedir(location);
+ projectScanner.setIncludes(new String[] {"**/.project"}); //$NON-NLS-1$
+ projectScanner.scan();
+
+ String[] projectFiles = projectScanner.getIncludedFiles();
+ if(projectFiles!=null && projectFiles.length>0) {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ boolean res = MessageDialog.openConfirm(Display.getDefault().getActiveShell(), //
+ Messages.MavenProjectCheckoutJob_confirm_title, //
+ Messages.MavenProjectCheckoutJob_confirm_message);
+ if(res) {
+ IWizard wizard = new ProjectsImportWizard(collectedLocations.get(0));
+ WizardDialog dialog = new WizardDialog(Display.getDefault().getActiveShell(), wizard);
+ dialog.open();
+ } else {
+ cleanup(collectedLocations);
+ }
+ }
+ });
+ return;
+ }
+
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ boolean res = MessageDialog.openConfirm(Display.getDefault().getActiveShell(), //
+ Messages.MavenProjectCheckoutJob_confirm2_title, //
+ Messages.MavenProjectCheckoutJob_confirm2_message);
+ if(res) {
+ Clipboard clipboard = new Clipboard(Display.getDefault());
+ clipboard.setContents(new Object[] { location }, new Transfer[] { TextTransfer.getInstance() });
+
+ NewProjectAction newProjectAction = new NewProjectAction(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+ newProjectAction.run();
+ } else {
+ cleanup(collectedLocations);
+ }
+ }
+ });
+ return;
+ }
+
+ cleanup(collectedLocations);
+ }
+
+ if(checkoutAllProjects) {
+ final MavenPlugin plugin = MavenPlugin.getDefault();
+ WorkspaceJob job = new WorkspaceJob(Messages.MavenProjectCheckoutJob_job) {
+ public IStatus runInWorkspace(IProgressMonitor monitor) {
+ Set<MavenProjectInfo> projectSet = plugin.getProjectConfigurationManager().collectProjects(projects);
+
+ try {
+ plugin.getProjectConfigurationManager().importProjects(projectSet, configuration, monitor);
+ } catch(CoreException ex) {
+ plugin.getConsole().logError("Projects imported with errors");
+ return ex.getStatus();
+ }
+
+ return Status.OK_STATUS;
+ }
+ };
+ ISchedulingRule rule = ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(ResourcesPlugin.getWorkspace().getRoot());
+ job.setRule(rule);
+ job.schedule();
+
+ } else {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ MavenImportWizard wizard = new MavenImportWizard(configuration, collectedLocations);
+ WizardDialog dialog = new WizardDialog(Display.getDefault().getActiveShell(), wizard);
+ int res = dialog.open();
+ if(res == Window.CANCEL) {
+ cleanup(collectedLocations);
+ }
+ }
+ });
+ }
+ }
+
+ protected void cleanup(List<String> locations) {
+ MavenConsole console = MavenPlugin.getDefault().getConsole();
+ for(String location : locations) {
+ try {
+ FileUtils.deleteDirectory(location);
+ } catch(IOException ex) {
+ String msg = "Can't delete " + location;
+ console.logError(msg + "; " + (ex.getMessage()==null ? ex.toString() : ex.getMessage())); //$NON-NLS-1$
+ MavenLogger.log(msg, ex);
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectSelectionDialog.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectSelectionDialog.java
new file mode 100644
index 00000000..77db0415
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectSelectionDialog.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.ui.dialogs.AbstractMavenDialog;
+
+
+/**
+ * A simple dialog allowing the selection of Maven projects and subfolders containing POMs.
+ */
+public class MavenProjectSelectionDialog extends AbstractMavenDialog {
+
+ protected static final String DIALOG_SETTINGS = MavenProjectSelectionDialog.class.getName();
+
+ protected static final long SEARCH_DELAY = 500L; //in milliseconds
+
+ private FilteredTree filteredTree;
+
+ private boolean useCheckboxTree;
+
+ /** Creates a dialog instance. */
+ public MavenProjectSelectionDialog(Shell parent, boolean useCheckboxTree) {
+ this(parent);
+ this.useCheckboxTree = useCheckboxTree;
+ }
+
+ /** Creates a dialog instance. */
+ public MavenProjectSelectionDialog(Shell parent) {
+ super(parent, DIALOG_SETTINGS);
+
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ setTitle(Messages.getString("projectSelectionDialog.title")); //$NON-NLS-1$
+ }
+
+ /** Produces the result of the selection. */
+ protected void computeResult() {
+ if(useCheckboxTree) {
+ List<Object> result = new ArrayList<Object>();
+ collectCheckedItems(getViewer().getTree().getItems(), result);
+ setResult(result);
+ } else {
+ setResult(((IStructuredSelection) getViewer().getSelection()).toList());
+ }
+ }
+
+ private void collectCheckedItems(TreeItem[] items, List<Object> list) {
+ for(TreeItem item : items) {
+ if(item.getChecked()) {
+ Object data = item.getData();
+ if(data != null) {
+ list.add(data);
+ }
+ }
+ collectCheckedItems(item.getItems(), list);
+ }
+ }
+
+ /** Creates the dialog controls. */
+ protected Control createDialogArea(Composite parent) {
+ readSettings();
+
+ Composite composite = (Composite) super.createDialogArea(parent);
+
+ filteredTree = new FilteredTree(composite, SWT.BORDER | (useCheckboxTree ? SWT.CHECK : 0), new PatternFilter(),
+ true);
+ filteredTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ getViewer().setContentProvider(new MavenContainerContentProvider());
+ getViewer().setLabelProvider(WorkbenchLabelProvider.getDecoratingWorkbenchLabelProvider());
+ getViewer().setInput(ResourcesPlugin.getWorkspace());
+
+ getViewer().addDoubleClickListener(new IDoubleClickListener() {
+ public void doubleClick(DoubleClickEvent event) {
+ okPressed();
+ }
+ });
+
+ return composite;
+ }
+
+ protected void okPressed() {
+ super.okPressed();
+ }
+
+ protected TreeViewer getViewer() {
+ return filteredTree.getViewer();
+ }
+
+ /** The content provider class. */
+ protected static class MavenContainerContentProvider implements ITreeContentProvider {
+
+ /** Returns the children of the parent node. */
+ public Object[] getChildren(Object parent) {
+ if(parent instanceof IWorkspace) {
+ IProject[] projects = ((IWorkspace) parent).getRoot().getProjects();
+
+ List<IProject> children = new ArrayList<IProject>();
+ for(IProject project : projects) {
+ try {
+ if(project.isOpen() && project.hasNature(IMavenConstants.NATURE_ID)) {
+ children.add(project);
+ }
+ } catch(CoreException e) {
+ MavenLogger.log("Error checking project: " + e.getMessage(), e);
+ }
+ }
+ return children.toArray();
+ } else if(parent instanceof IContainer) {
+ IContainer container = (IContainer) parent;
+ if(container.isAccessible()) {
+ try {
+ List<IResource> children = new ArrayList<IResource>();
+ IResource[] members = container.members();
+ for(int i = 0; i < members.length; i++ ) {
+ if(members[i] instanceof IContainer
+ && ((IContainer) members[i]).exists(new Path(IMavenConstants.POM_FILE_NAME))) {
+ children.add(members[i]);
+ }
+ }
+ return children.toArray();
+ } catch(CoreException e) {
+ MavenLogger.log("Error checking container: " + e.getMessage(), e);
+ }
+ }
+ }
+ return new Object[0];
+ }
+
+ /** Returns the parent of the given element. */
+ public Object getParent(Object element) {
+ if(element instanceof IResource) {
+ return ((IResource) element).getParent();
+ }
+ return null;
+ }
+
+ /** Returns true if the element has any children. */
+ public boolean hasChildren(Object element) {
+ return getChildren(element).length > 0;
+ }
+
+ /** Disposes of any resources used. */
+ public void dispose() {
+ }
+
+ /** Handles the input change. */
+ public void inputChanged(Viewer viewer, Object arg1, Object arg2) {
+ }
+
+ /** Returns the elements of the given root. */
+ public Object[] getElements(Object element) {
+ return getChildren(element);
+ }
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizard.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizard.java
new file mode 100644
index 00000000..48e3630d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizard.java
@@ -0,0 +1,358 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.resources.WorkspaceJob;
+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.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.INewWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.progress.IProgressConstants;
+
+import org.apache.maven.archetype.catalog.Archetype;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.actions.OpenMavenConsoleAction;
+import org.eclipse.m2e.core.actions.SelectionUtil;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+
+
+/**
+ * Simple project wizard for creating a new Maven2 project.
+ * <p>
+ * The wizard provides the following functionality to the user:
+ * <ul>
+ * <li>Create the project in the workspace or at some external location.</li>
+ * <li>Provide information about the Maven2 artifact to create.</li>
+ * <li>Choose directories of the default Maven2 directory structure to create.</li>
+ * <li>Choose a set of Maven2 dependencies for the project.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Once the wizard has finished, the following resources are created and configured:
+ * <ul>
+ * <li>A POM file containing the given artifact information and the chosen dependencies.</li>
+ * <li>The chosen Maven2 directories.</li>
+ * <li>The .classpath file is configured to hold appropriate entries for the Maven2 directories created as well as the
+ * Java and Maven2 classpath containers.</li>
+ * </ul>
+ * </p>
+ */
+public class MavenProjectWizard extends Wizard implements INewWizard {
+
+ /** The wizard page for gathering general project information. */
+ protected MavenProjectWizardLocationPage locationPage;
+
+ /** The archetype selection page. */
+ protected MavenProjectWizardArchetypePage archetypePage;
+
+ /** The wizard page for gathering Maven2 project information. */
+ protected MavenProjectWizardArtifactPage artifactPage;
+
+ /** The wizard page for gathering archetype project information. */
+ protected MavenProjectWizardArchetypeParametersPage parametersPage;
+
+ /** The wizard page for choosing the Maven2 dependencies to use. */
+ protected MavenDependenciesWizardPage dependenciesPage;
+
+ ProjectImportConfiguration configuration;
+
+ protected Button simpleProject;
+
+ private IStructuredSelection selection;
+
+ /**
+ * Default constructor. Sets the title and image of the wizard.
+ */
+ public MavenProjectWizard() {
+ super();
+ setWindowTitle(Messages.getString("wizard.project.title")); //$NON-NLS-1$
+ setDefaultPageImageDescriptor(MavenImages.WIZ_NEW_PROJECT);
+ setNeedsProgressMonitor(true);
+ }
+
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ this.selection = selection;
+ }
+
+ public void addPages() {
+ configuration = new ProjectImportConfiguration();
+ configuration.setWorkingSet(SelectionUtil.getSelectedWorkingSet(selection));
+
+ locationPage = new MavenProjectWizardLocationPage(configuration, //
+ Messages.getString("wizard.project.page.project.title"), // //$NON-NLS-1$
+ Messages.getString("wizard.project.page.project.description")) { //$NON-NLS-1$
+
+ protected void createAdditionalControls(Composite container) {
+ simpleProject = new Button(container, SWT.CHECK);
+ simpleProject.setText(Messages.getString("wizard.project.page.project.simpleProject")); //$NON-NLS-1$
+ simpleProject.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 3, 1));
+ simpleProject.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ validate();
+ }
+ });
+
+ Label label = new Label(container, SWT.NONE);
+ GridData labelData = new GridData(SWT.FILL, SWT.TOP, false, false, 3, 1);
+ labelData.heightHint = 10;
+ label.setLayoutData(labelData);
+ }
+
+ /** Skips the archetype selection page if the user chooses a simple project. */
+ public IWizardPage getNextPage() {
+ return getPage(simpleProject.getSelection() ? "MavenProjectWizardArtifactPage" : "MavenProjectWizardArchetypePage"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ };
+ locationPage.setLocationPath(SelectionUtil.getSelectedLocation(selection));
+
+ archetypePage = new MavenProjectWizardArchetypePage(configuration);
+ parametersPage = new MavenProjectWizardArchetypeParametersPage(configuration);
+ artifactPage = new MavenProjectWizardArtifactPage(configuration);
+ dependenciesPage = new MavenDependenciesWizardPage(configuration, //
+ Messages.getString("wizard.project.page.dependencies.title"), // //$NON-NLS-1$
+ Messages.getString("wizard.project.page.dependencies.description")); //$NON-NLS-1$
+ dependenciesPage.setDependencies(new Dependency[0]);
+ dependenciesPage.setShowScope(true);
+
+ addPage(locationPage);
+ addPage(archetypePage);
+ addPage(parametersPage);
+ addPage(artifactPage);
+ addPage(dependenciesPage);
+ }
+
+ /** Adds the listeners after the page controls are created. */
+ public void createPageControls(Composite pageContainer) {
+ super.createPageControls(pageContainer);
+
+ simpleProject.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ boolean isSimpleproject = simpleProject.getSelection();
+ archetypePage.setUsed(!isSimpleproject);
+ parametersPage.setUsed(!isSimpleproject);
+ artifactPage.setUsed(isSimpleproject);
+ getContainer().updateButtons();
+ }
+ });
+
+ archetypePage.addArchetypeSelectionListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent selectionchangedevent) {
+ parametersPage.setArchetype(archetypePage.getArchetype());
+ getContainer().updateButtons();
+ }
+ });
+
+// locationPage.addProjectNameListener(new ModifyListener() {
+// public void modifyText(ModifyEvent e) {
+// parametersPage.setProjectName(locationPage.getProjectName());
+// artifactPage.setProjectName(locationPage.getProjectName());
+// }
+// });
+ }
+
+ /** Returns the model. */
+ public Model getModel() {
+ if(simpleProject.getSelection()) {
+ return artifactPage.getModel();
+ }
+ return parametersPage.getModel();
+ }
+
+ /**
+ * To perform the actual project creation, an operation is created and run using this wizard as execution context.
+ * That way, messages about the progress of the project creation are displayed inside the wizard.
+ */
+ public boolean performFinish() {
+ // First of all, we extract all the information from the wizard pages.
+ // Note that this should not be done inside the operation we will run
+ // since many of the wizard pages' methods can only be invoked from within
+ // the SWT event dispatcher thread. However, the operation spawns a new
+ // separate thread to perform the actual work, i.e. accessing SWT elements
+ // from within that thread would lead to an exception.
+
+// final IProject project = locationPage.getProjectHandle();
+// final String projectName = locationPage.getProjectName();
+
+ // Get the location where to create the project. For some reason, when using
+ // the default workspace location for a project, we have to pass null
+ // instead of the actual location.
+ final Model model = getModel();
+ final String projectName = configuration.getProjectName(model);
+ IStatus nameStatus = configuration.validateProjectName(model);
+ if(!nameStatus.isOK()) {
+ MessageDialog.openError(getShell(), Messages.getString("wizard.project.job.failed", projectName), nameStatus.getMessage()); //$NON-NLS-1$
+ return false;
+ }
+
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+
+ final IPath location = locationPage.isInWorkspace() ? null : locationPage.getLocationPath();
+ final IWorkspaceRoot root = workspace.getRoot();
+ final IProject project = configuration.getProject(root, model);
+
+ boolean pomExists = ( locationPage.isInWorkspace() ?
+ root.getLocation().append(project.getName()) : location ).append(IMavenConstants.POM_FILE_NAME).toFile().exists();
+ if ( pomExists ) {
+ MessageDialog.openError(getShell(), Messages.getString("wizard.project.job.failed", projectName), Messages.getString("wizard.project.error.pomAlreadyExists")); //$NON-NLS-1$ //$NON-NLS-2$
+ return false;
+ }
+
+ final Job job;
+
+ final MavenPlugin plugin = MavenPlugin.getDefault();
+
+ if(simpleProject.getSelection()) {
+ @SuppressWarnings("unchecked")
+ List<Dependency> modelDependencies = model.getDependencies();
+ modelDependencies.addAll(Arrays.asList(dependenciesPage.getDependencies()));
+
+ final String[] folders = artifactPage.getFolders();
+
+ job = new WorkspaceJob(Messages.getString("wizard.project.job.creatingProject", projectName)) { //$NON-NLS-1$
+ public IStatus runInWorkspace(IProgressMonitor monitor) {
+ setProperty(IProgressConstants.ACTION_PROPERTY, new OpenMavenConsoleAction());
+ try {
+ plugin.getProjectConfigurationManager().createSimpleProject(project, location, model, folders, //
+ configuration, monitor);
+ return Status.OK_STATUS;
+ } catch(CoreException e) {
+ return e.getStatus();
+ } finally {
+ monitor.done();
+ }
+ }
+ };
+
+ } else {
+ final Archetype archetype = archetypePage.getArchetype();
+
+ final String groupId = model.getGroupId();
+ final String artifactId = model.getArtifactId();
+ final String version = model.getVersion();
+ final String javaPackage = parametersPage.getJavaPackage();
+ final Properties properties = parametersPage.getProperties();
+
+ job = new WorkspaceJob(Messages.getString("wizard.project.job.creating", archetype.getArtifactId())) { //$NON-NLS-1$
+ public IStatus runInWorkspace(IProgressMonitor monitor) {
+ setProperty(IProgressConstants.ACTION_PROPERTY, new OpenMavenConsoleAction());
+ try {
+ plugin.getProjectConfigurationManager().createArchetypeProject(project, location, archetype, //
+ groupId, artifactId, version, javaPackage, properties, configuration, monitor);
+ return Status.OK_STATUS;
+ } catch(CoreException e) {
+ return e.getStatus();
+ } finally {
+ monitor.done();
+ }
+ }
+ };
+ }
+
+ job.addJobChangeListener(new JobChangeAdapter() {
+ public void done(IJobChangeEvent event) {
+ final IStatus result = event.getResult();
+ if(!result.isOK()) {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ MessageDialog.openError(getShell(), //
+ Messages.getString("wizard.project.job.failed", projectName), result.getMessage()); //$NON-NLS-1$
+ }
+ });
+ }
+ }
+ });
+
+
+ job.setRule(plugin.getProjectConfigurationManager().getRule());
+ job.schedule();
+
+// ProjectListener listener = new ProjectListener();
+// workspace.addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE);
+// try {
+// job.setRule(plugin.getProjectConfigurationManager().getRule());
+// job.schedule();
+//
+// // MNGECLIPSE-766 wait until new project is created
+// while(listener.getNewProject() == null && (job.getState() & (Job.WAITING | Job.RUNNING)) > 0) {
+// try {
+// Thread.sleep(100L);
+// } catch (InterruptedException ex) {
+// // ignore
+// }
+// }
+//
+// } finally {
+// workspace.removeResourceChangeListener(listener);
+// }
+
+ return true;
+ }
+
+
+// static class ProjectListener implements IResourceChangeListener {
+// private IProject newProject = null;
+//
+// public void resourceChanged(IResourceChangeEvent event) {
+// IResourceDelta root = event.getDelta();
+// IResourceDelta[] projectDeltas = root.getAffectedChildren();
+// for (int i = 0; i < projectDeltas.length; i++) {
+// IResourceDelta delta = projectDeltas[i];
+// IResource resource = delta.getResource();
+// if (delta.getKind() == IResourceDelta.ADDED) {
+// newProject = (IProject)resource;
+// }
+// }
+// }
+// /**
+// * Gets the newProject.
+// * @return Returns a IProject
+// */
+// public IProject getNewProject() {
+// return newProject;
+// }
+// }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArchetypePage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArchetypePage.java
new file mode 100644
index 00000000..3e8ceb57
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArchetypePage.java
@@ -0,0 +1,953 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.IOpenListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.OpenEvent;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.IWizardContainer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+
+import org.apache.maven.archetype.catalog.Archetype;
+import org.apache.maven.archetype.catalog.ArchetypeCatalog;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.DefaultArtifactRepository;
+import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory;
+import org.eclipse.m2e.core.archetype.ArchetypeCatalogFactory.NexusIndexerCatalogFactory;
+import org.eclipse.m2e.core.archetype.ArchetypeManager;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.index.IMutableIndex;
+import org.eclipse.m2e.core.index.IndexListener;
+import org.eclipse.m2e.core.index.IndexManager;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+import org.eclipse.m2e.core.repository.IRepository;
+import org.eclipse.m2e.core.util.M2EUtils;
+
+
+/**
+ * Maven Archetype selection wizard page presents the user with a list of available Maven Archetypes available for
+ * creating new project.
+ */
+public class MavenProjectWizardArchetypePage extends AbstractMavenWizardPage implements IndexListener {
+
+ private static final String KEY_CATALOG = "catalog"; //$NON-NLS-1$
+
+ private static final String ALL_CATALOGS = org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_all;
+
+ public static final Comparator<Archetype> ARCHETYPE_COMPARATOR = new Comparator<Archetype>() {
+
+ public int compare(Archetype a1, Archetype a2) {
+ String g1 = a1.getGroupId();
+ String g2 = a2.getGroupId();
+ int res = g1.compareTo(g2);
+ if(res != 0) {
+ return res;
+ }
+
+ String i1 = a1.getArtifactId();
+ String i2 = a2.getArtifactId();
+ res = i1.compareTo(i2);
+ if(res != 0) {
+ return res;
+ }
+
+ String v1 = a1.getVersion();
+ String v2 = a2.getVersion();
+ if(v1 == null) {
+ return v2 == null ? 0 : -1;
+ }
+ return v1.compareTo(v2);
+ }
+
+ };
+
+ ComboViewer catalogsComboViewer;
+
+ Text filterText;
+
+ /** the archetype table viewer */
+ TableViewer viewer;
+
+ /** the description value label */
+ Text descriptionText;
+
+ Button showLastVersionButton;
+
+ Button includeShapshotsButton;
+
+ Button addArchetypeButton;
+
+ /** the list of available archetypes */
+ volatile Collection<Archetype> archetypes;
+
+ Collection<Archetype> lastVersionArchetypes;
+
+ /** a flag indicating if the archetype selection is actually used in the wizard */
+ private boolean isUsed = true;
+
+ ArchetypeCatalogFactory catalogFactory = null;
+
+ /**
+ * Default constructor. Sets the title and description of this wizard page and marks it as not being complete as user
+ * input is required for continuing.
+ */
+ public MavenProjectWizardArchetypePage(ProjectImportConfiguration projectImportConfiguration) {
+ super("MavenProjectWizardArchetypePage", projectImportConfiguration); //$NON-NLS-1$
+ setTitle(Messages.getString("wizard.project.page.archetype.title")); //$NON-NLS-1$
+ setDescription(Messages.getString("wizard.project.page.archetype.description")); //$NON-NLS-1$
+ setPageComplete(false);
+ }
+
+ /** Creates the page controls. */
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(3, false));
+
+ createViewer(composite);
+
+ createAdvancedSettings(composite, new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1));
+
+ MavenPlugin.getDefault().getIndexManager().addIndexListener(this);
+ setControl(composite);
+ }
+
+ /** Creates the archetype table viewer. */
+ private void createViewer(Composite parent) {
+ Label catalogsLabel = new Label(parent, SWT.NONE);
+ catalogsLabel.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_lblCatalog);
+
+ Composite catalogsComposite = new Composite(parent, SWT.NONE);
+ GridLayout catalogsCompositeLayout = new GridLayout();
+ catalogsCompositeLayout.marginWidth = 0;
+ catalogsCompositeLayout.marginHeight = 0;
+ catalogsCompositeLayout.numColumns = 2;
+ catalogsComposite.setLayout(catalogsCompositeLayout);
+ catalogsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));
+
+ catalogsComboViewer = new ComboViewer(catalogsComposite);
+ catalogsComboViewer.getControl().setData("name", "catalogsCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+ catalogsComboViewer.getCombo().setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ catalogsComboViewer.setContentProvider(new IStructuredContentProvider() {
+ public Object[] getElements(Object input) {
+
+ if(input instanceof Collection) {
+ return ((Collection<?>) input).toArray();
+ }
+ return new Object[0];
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ public void dispose() {
+ }
+ });
+
+ catalogsComboViewer.setLabelProvider(new LabelProvider() {
+ public String getText(Object element) {
+ if(element instanceof ArchetypeCatalogFactory) {
+ return ((ArchetypeCatalogFactory) element).getDescription();
+ } else if(element instanceof String) {
+ return element.toString();
+ }
+ return super.getText(element);
+ }
+ });
+
+ catalogsComboViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ ISelection selection = event.getSelection();
+ if(selection instanceof IStructuredSelection) {
+ Object factory = ((IStructuredSelection) selection).getFirstElement();
+ if(factory instanceof ArchetypeCatalogFactory) {
+ catalogFactory = (ArchetypeCatalogFactory) factory;
+ } else if(factory instanceof String) {
+ catalogFactory = null;
+ }
+ reloadViewer();
+ } else {
+ catalogFactory = null;
+ loadArchetypes(null, null, null);
+ }
+ //remember what was switched to here
+ if(dialogSettings != null && catalogFactory != null) {
+ dialogSettings.put(KEY_CATALOG, catalogFactory.getId());
+ }
+ }
+ });
+
+ final ArchetypeManager archetypeManager = MavenPlugin.getDefault().getArchetypeManager();
+ Collection<ArchetypeCatalogFactory> archetypeCatalogs = archetypeManager.getArchetypeCatalogs();
+ ArrayList allCatalogs = new ArrayList(archetypeManager.getArchetypeCatalogs());
+ allCatalogs.add(0, ALL_CATALOGS);
+ catalogsComboViewer.setInput(allCatalogs);
+
+ Button configureButton = new Button(catalogsComposite, SWT.NONE);
+ configureButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ configureButton.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_btnConfigure);
+ configureButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ PreferencesUtil.createPreferenceDialogOn(getShell(),
+ "org.eclipse.m2e.preferences.MavenArchetypesPreferencePage", null, null).open(); //$NON-NLS-1$
+
+ if(catalogFactory == null || archetypeManager.getArchetypeCatalogFactory(catalogFactory.getId()) == null) {
+ catalogFactory = archetypeManager.getArchetypeCatalogFactory(NexusIndexerCatalogFactory.ID);
+ }
+
+ catalogsComboViewer.setInput(archetypeManager.getArchetypeCatalogs());
+ catalogsComboViewer.setSelection(new StructuredSelection(catalogFactory));
+ }
+ });
+
+ Label filterLabel = new Label(parent, SWT.NONE);
+ filterLabel.setLayoutData(new GridData());
+ filterLabel.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_lblFilter);
+
+ QuickViewerFilter quickViewerFilter = new QuickViewerFilter();
+ LastVersionFilter versionFilter = new LastVersionFilter();
+ IncludeSnapshotsFilter snapshotsFilter = new IncludeSnapshotsFilter();
+
+ filterText = new Text(parent, SWT.BORDER);
+ filterText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ filterText.addModifyListener(quickViewerFilter);
+ filterText.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent e) {
+ if(e.keyCode == SWT.ARROW_DOWN) {
+ viewer.getTable().setFocus();
+ viewer.getTable().setSelection(0);
+
+ viewer.setSelection(new StructuredSelection(viewer.getElementAt(0)), true);
+ }
+ }
+ });
+
+ ToolBar toolBar = new ToolBar(parent, SWT.FLAT);
+ toolBar.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+
+ final ToolItem clearToolItem = new ToolItem(toolBar, SWT.PUSH);
+ clearToolItem.setEnabled(false);
+ clearToolItem.setImage(MavenImages.IMG_CLEAR);
+ clearToolItem.setDisabledImage(MavenImages.IMG_CLEAR_DISABLED);
+ clearToolItem.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ filterText.setText(""); //$NON-NLS-1$
+ }
+ });
+
+ filterText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ clearToolItem.setEnabled(filterText.getText().length() > 0);
+ }
+ });
+
+ SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
+ GridData gd_sashForm = new GridData(SWT.FILL, SWT.FILL, false, true, 3, 1);
+ // gd_sashForm.widthHint = 500;
+ gd_sashForm.heightHint = 200;
+ sashForm.setLayoutData(gd_sashForm);
+ sashForm.setLayout(new GridLayout());
+
+ Composite composite1 = new Composite(sashForm, SWT.NONE);
+ GridLayout gridLayout1 = new GridLayout();
+ gridLayout1.horizontalSpacing = 0;
+ gridLayout1.marginWidth = 0;
+ gridLayout1.marginHeight = 0;
+ composite1.setLayout(gridLayout1);
+
+ viewer = new TableViewer(composite1, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION);
+ Table table = viewer.getTable();
+ table.setData("name", "archetypesTable"); //$NON-NLS-1$ //$NON-NLS-2$
+ table.setHeaderVisible(true);
+
+ TableColumn column1 = new TableColumn(table, SWT.LEFT);
+ column1.setWidth(150);
+ column1.setText(Messages.getString("wizard.project.page.archetype.column.groupId")); //$NON-NLS-1$
+
+ TableColumn column0 = new TableColumn(table, SWT.LEFT);
+ column0.setWidth(150);
+ column0.setText(Messages.getString("wizard.project.page.archetype.column.artifactId")); //$NON-NLS-1$
+
+ TableColumn column2 = new TableColumn(table, SWT.LEFT);
+ column2.setWidth(100);
+ column2.setText(Messages.getString("wizard.project.page.archetype.column.version")); //$NON-NLS-1$
+
+ GridData tableData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ tableData.widthHint = 400;
+ tableData.heightHint = 200;
+ table.setLayoutData(tableData);
+
+ viewer.setLabelProvider(new ArchetypeLabelProvider());
+
+ viewer.setComparator(new ViewerComparator() {
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ return ARCHETYPE_COMPARATOR.compare((Archetype) e1, (Archetype) e2);
+ }
+ });
+
+ viewer.addFilter(quickViewerFilter);
+ viewer.addFilter(versionFilter);
+ viewer.addFilter(snapshotsFilter);
+
+ viewer.setContentProvider(new IStructuredContentProvider() {
+ public Object[] getElements(Object inputElement) {
+ if(inputElement instanceof Collection) {
+ return ((Collection<?>) inputElement).toArray();
+ }
+ return new Object[0];
+ }
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+ });
+
+ viewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ Archetype archetype = getArchetype();
+ if(archetype != null) {
+ String repositoryUrl = archetype.getRepository();
+ String description = archetype.getDescription();
+
+ String text = description == null ? "" : description; //$NON-NLS-1$
+ text = text.replaceAll("\n", "").replaceAll("\\s{2,}", " "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+
+ if(repositoryUrl != null) {
+ text += text.length() > 0 ? "\n" + repositoryUrl : repositoryUrl; //$NON-NLS-1$
+ }
+
+ descriptionText.setText(text);
+ setPageComplete(true);
+ } else {
+ descriptionText.setText(""); //$NON-NLS-1$
+ setPageComplete(false);
+ }
+ }
+ });
+
+ viewer.addOpenListener(new IOpenListener() {
+ public void open(OpenEvent openevent) {
+ if(canFlipToNextPage()) {
+ getContainer().showPage(getNextPage());
+ }
+ }
+ });
+
+ Composite composite2 = new Composite(sashForm, SWT.NONE);
+ GridLayout gridLayout2 = new GridLayout();
+ gridLayout2.marginHeight = 0;
+ gridLayout2.marginWidth = 0;
+ gridLayout2.horizontalSpacing = 0;
+ composite2.setLayout(gridLayout2);
+
+ descriptionText = new Text(composite2, SWT.WRAP | SWT.V_SCROLL | SWT.READ_ONLY | SWT.MULTI | SWT.BORDER);
+
+ GridData descriptionTextData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ descriptionTextData.heightHint = 40;
+ descriptionText.setLayoutData(descriptionTextData);
+ //whole dialog resizes badly without the width hint to the desc text
+ descriptionTextData.widthHint = 250;
+ sashForm.setWeights(new int[] {80, 20});
+
+ Composite buttonComposite = new Composite(parent, SWT.NONE);
+ GridData gd_buttonComposite = new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1);
+ buttonComposite.setLayoutData(gd_buttonComposite);
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ gridLayout.numColumns = 3;
+ buttonComposite.setLayout(gridLayout);
+
+ showLastVersionButton = new Button(buttonComposite, SWT.CHECK);
+ showLastVersionButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
+ showLastVersionButton.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_btnLast);
+ showLastVersionButton.setSelection(true);
+ showLastVersionButton.addSelectionListener(versionFilter);
+
+ includeShapshotsButton = new Button(buttonComposite, SWT.CHECK);
+ GridData buttonData = new GridData(SWT.LEFT, SWT.CENTER, true, false);
+ buttonData.horizontalIndent = 25;
+ includeShapshotsButton.setLayoutData(buttonData);
+ includeShapshotsButton.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_btnSnapshots);
+ includeShapshotsButton.setSelection(false);
+ includeShapshotsButton.addSelectionListener(snapshotsFilter);
+
+ addArchetypeButton = new Button(buttonComposite, SWT.NONE);
+ addArchetypeButton.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_btnAdd);
+ addArchetypeButton.setData("name", "addArchetypeButton"); //$NON-NLS-1$ //$NON-NLS-2$
+ buttonData = new GridData(SWT.RIGHT, SWT.CENTER, true, false);
+ buttonData.horizontalIndent = 35;
+ addArchetypeButton.setLayoutData(buttonData);
+
+ addArchetypeButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ CustomArchetypeDialog dialog = new CustomArchetypeDialog(getShell(),
+ org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_add_title);
+ if(dialog.open() == Window.OK) {
+ String archetypeGroupId = dialog.getArchetypeGroupId();
+ String archetypeArtifactId = dialog.getArchetypeArtifactId();
+ String archetypeVersion = dialog.getArchetypeVersion();
+ String repositoryUrl = dialog.getRepositoryUrl();
+ downloadArchetype(archetypeGroupId, archetypeArtifactId, archetypeVersion, repositoryUrl);
+ }
+ }
+ });
+ }
+
+ protected IWizardContainer getContainer() {
+ return super.getContainer();
+ }
+
+ public void addArchetypeSelectionListener(ISelectionChangedListener listener) {
+ viewer.addSelectionChangedListener(listener);
+ }
+
+ public void dispose() {
+ MavenPlugin.getDefault().getIndexManager().removeIndexListener(this);
+ super.dispose();
+ }
+
+ public List<Archetype> getArchetypesForCatalog() {
+ if(catalogFactory == null) {
+ return getAllArchetypes();
+ }
+ try {
+ return catalogFactory.getArchetypeCatalog().getArchetypes();
+
+ } catch(CoreException ce) {
+ setErrorMessage(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_error_read);
+ return null;
+ }
+ }
+
+ private List<Archetype> getAllArchetypes() {
+ ArchetypeManager manager = MavenPlugin.getDefault().getArchetypeManager();
+ Collection<ArchetypeCatalogFactory> archetypeCatalogs = manager.getArchetypeCatalogs();
+ ArrayList<Archetype> list = new ArrayList<Archetype>();
+
+ for(ArchetypeCatalogFactory catalog : archetypeCatalogs) {
+ try {
+ //temporary hack to get around 'Test Remote Catalog' blowing up on download
+ //described in https://issues.sonatype.org/browse/MNGECLIPSE-1792
+ if(catalog.getDescription().startsWith("Test")) { //$NON-NLS-1$
+ continue;
+ }
+ @SuppressWarnings("unchecked")
+ List arcs = catalog.getArchetypeCatalog().getArchetypes();
+ if(arcs != null) {
+ list.addAll(arcs);
+ }
+ } catch(Exception ce) {
+ MavenLogger.log("Unable to read archetype catalog: " + catalog.getId(), ce);
+ }
+ }
+ return list;
+ }
+
+ /** Loads the available archetypes. */
+ void loadArchetypes(final String groupId, final String artifactId, final String version) {
+ Job job = new Job(Messages.getString("wizard.project.page.archetype.retrievingArchetypes")) { //$NON-NLS-1$
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ List<Archetype> catalogArchetypes = getArchetypesForCatalog();
+
+ if(catalogArchetypes == null || catalogArchetypes.size() == 0) {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ if(catalogFactory != null && "Nexus Indexer".equals(catalogFactory.getDescription())) { //$NON-NLS-1$
+ setErrorMessage(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_error_no);
+ }
+ }
+ });
+ } else {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ setErrorMessage(null);
+ }
+ });
+ }
+ if(catalogArchetypes == null) {
+ return Status.CANCEL_STATUS;
+ }
+ TreeSet<Archetype> archs = new TreeSet<Archetype>(ARCHETYPE_COMPARATOR);
+ archs.addAll(catalogArchetypes);
+ archetypes = archs;
+
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ updateViewer(groupId, artifactId, version);
+ }
+ });
+ } catch(Exception e) {
+ monitor.done();
+ return Status.CANCEL_STATUS;
+ }
+
+ return Status.OK_STATUS;
+ }
+ };
+ job.schedule();
+ }
+
+ public Set<Archetype> filterVersions(Collection<Archetype> archetypes) {
+ HashMap<String, Archetype> filteredArchetypes = new HashMap<String, Archetype>();
+
+ for(Archetype currentArchetype : archetypes) {
+ String key = getArchetypeKey(currentArchetype);
+ Archetype archetype = filteredArchetypes.get(key);
+ if(archetype == null) {
+ filteredArchetypes.put(key, currentArchetype);
+ } else {
+ DefaultArtifactVersion currentVersion = new DefaultArtifactVersion(currentArchetype.getVersion());
+ DefaultArtifactVersion version = new DefaultArtifactVersion(archetype.getVersion());
+ if(currentVersion.compareTo(version) > 0) {
+ filteredArchetypes.put(key, currentArchetype);
+ }
+ }
+ }
+
+ TreeSet<Archetype> result = new TreeSet<Archetype>(new Comparator<Archetype>() {
+ public int compare(Archetype a1, Archetype a2) {
+ String k1 = a1.getGroupId() + ":" + a1.getArtifactId() + ":" + a1.getVersion(); //$NON-NLS-1$ //$NON-NLS-2$
+ String k2 = a2.getGroupId() + ":" + a2.getArtifactId() + ":" + a2.getVersion(); //$NON-NLS-1$ //$NON-NLS-2$
+ return k1.compareTo(k2);
+ }
+ });
+ result.addAll(filteredArchetypes.values());
+ return result;
+ }
+
+ private String getArchetypeKey(Archetype archetype) {
+ return archetype.getGroupId() + ":" + archetype.getArtifactId(); //$NON-NLS-1$
+ }
+
+ ArchetypeCatalog getArchetypeCatalog() throws CoreException {
+ return catalogFactory == null ? null : catalogFactory.getArchetypeCatalog();
+ }
+
+ /** Sets the flag that the archetype selection is used in the wizard. */
+ public void setUsed(boolean isUsed) {
+ this.isUsed = isUsed;
+ }
+
+ /** Overrides the default to return "true" if the page is not used. */
+ public boolean isPageComplete() {
+ return !isUsed || super.isPageComplete();
+ }
+
+ /** Sets the focus to the table component. */
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+
+ if(visible) {
+ ArchetypeManager archetypeManager = MavenPlugin.getDefault().getArchetypeManager();
+ String catalogId = dialogSettings.get(KEY_CATALOG);
+ catalogFactory = null;
+ if(catalogId != null) {
+ catalogFactory = archetypeManager.getArchetypeCatalogFactory(catalogId);
+ }
+ catalogsComboViewer.setSelection(new StructuredSelection(catalogFactory == null ? ALL_CATALOGS : catalogFactory));
+
+ viewer.getTable().setFocus();
+ Archetype selected = getArchetype();
+ if(selected != null) {
+ viewer.reveal(selected);
+ }
+ }
+ }
+
+ /** Returns the selected archetype. */
+ public Archetype getArchetype() {
+ return (Archetype) ((IStructuredSelection) viewer.getSelection()).getFirstElement();
+ }
+
+ void updateViewer(String groupId, String artifactId, String version) {
+ lastVersionArchetypes = filterVersions(archetypes);
+
+ viewer.setInput(archetypes);
+
+ selectArchetype(groupId, artifactId, version);
+
+ Table table = viewer.getTable();
+ int columnCount = table.getColumnCount();
+ int width = 0;
+ for(int i = 0; i < columnCount; i++ ) {
+ TableColumn column = table.getColumn(i);
+ column.pack();
+ width += column.getWidth();
+ }
+ GridData tableData = (GridData) table.getLayoutData();
+ int oldHint = tableData.widthHint;
+ if(width > oldHint) {
+ tableData.widthHint = width;
+ }
+ getShell().pack(true);
+ tableData.widthHint = oldHint;
+ }
+
+ protected void selectArchetype(String groupId, String artifactId, String version) {
+ Archetype archetype = findArchetype(groupId, artifactId, version);
+
+ Table table = viewer.getTable();
+ if(archetype != null) {
+ viewer.setSelection(new StructuredSelection(archetype), true);
+
+ int n = table.getSelectionIndex();
+ table.setSelection(n);
+ }
+ }
+
+ /** Locates an archetype with given ids. */
+ protected Archetype findArchetype(String groupId, String artifactId, String version) {
+ for(Archetype archetype : archetypes) {
+ if(archetype.getGroupId().equals(groupId) && archetype.getArtifactId().equals(artifactId)) {
+ if(version == null || version.equals(archetype.getVersion())) {
+ return archetype;
+ }
+ }
+ }
+
+ return version == null ? null : findArchetype(groupId, artifactId, null);
+ }
+
+ protected void downloadArchetype(final String archetypeGroupId, final String archetypeArtifactId,
+ final String archetypeVersion, final String repositoryUrl) {
+ final String archetypeName = archetypeGroupId + ":" + archetypeArtifactId + ":" + archetypeVersion; //$NON-NLS-1$ //$NON-NLS-2$
+
+ try {
+ getContainer().run(true, true, new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor) throws InterruptedException {
+ monitor.beginTask(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_task_downloading
+ + archetypeName, IProgressMonitor.UNKNOWN);
+
+ try {
+ final IMaven maven = MavenPlugin.getDefault().getMaven();
+
+ final MavenPlugin plugin = MavenPlugin.getDefault();
+
+ final List<ArtifactRepository> remoteRepositories;
+ if(repositoryUrl.length() == 0) {
+ remoteRepositories = maven.getArtifactRepositories(); // XXX should use ArchetypeManager.getArhetypeRepositories()
+ } else {
+ ArtifactRepository repository = new DefaultArtifactRepository( //
+ "archetype", repositoryUrl, new DefaultRepositoryLayout(), null, null); //$NON-NLS-1$
+ remoteRepositories = Collections.singletonList(repository);
+ }
+
+ monitor.subTask(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_task_resolving);
+ Artifact pomArtifact = maven.resolve(archetypeGroupId, archetypeArtifactId, archetypeVersion,
+ "pom", null, remoteRepositories, monitor); //$NON-NLS-1$
+ monitor.worked(1);
+ if(monitor.isCanceled()) {
+ throw new InterruptedException();
+ }
+
+ File pomFile = pomArtifact.getFile();
+ if(pomFile.exists()) {
+ monitor.subTask(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_task_resolving2);
+ Artifact jarArtifact = maven.resolve(archetypeGroupId, archetypeArtifactId, archetypeVersion,
+ "jar", null, remoteRepositories, monitor); //$NON-NLS-1$
+ monitor.worked(1);
+ if(monitor.isCanceled()) {
+ throw new InterruptedException();
+ }
+
+ File jarFile = jarArtifact.getFile();
+
+ monitor.subTask(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_task_reading);
+ monitor.worked(1);
+ if(monitor.isCanceled()) {
+ throw new InterruptedException();
+ }
+
+ monitor.subTask(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_task_indexing);
+ IndexManager indexManager = plugin.getIndexManager();
+ IMutableIndex localIndex = indexManager.getLocalIndex();
+ localIndex.addArtifact(jarFile, new ArtifactKey(pomArtifact));
+
+ //save out the archetype
+ //TODO move this logig out of UI code!
+ Archetype archetype = new Archetype();
+ archetype.setGroupId(archetypeGroupId);
+ archetype.setArtifactId(archetypeArtifactId);
+ archetype.setVersion(archetypeVersion);
+ archetype.setRepository(repositoryUrl);
+ org.apache.maven.archetype.Archetype archetyper = MavenPlugin.getDefault().getArchetype();
+ archetyper.updateLocalCatalog(archetype);
+
+ loadArchetypes(archetypeGroupId, archetypeArtifactId, archetypeVersion);
+ } else {
+ final Artifact pom = pomArtifact;
+ //the user tried to add an archetype that couldn't be resolved on the server
+ getShell().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ setErrorMessage(NLS.bind(
+ org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_error_resolve,
+ pom.toString()));
+ }
+ });
+ }
+
+ } catch(InterruptedException ex) {
+ throw ex;
+
+ } catch(final Exception ex) {
+ final String msg = NLS.bind(
+ org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_error_resolve2, archetypeName);
+ MavenLogger.log(msg, ex);
+ getShell().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ setErrorMessage(msg + "\n" + ex.toString()); //$NON-NLS-1$
+ }
+ });
+
+ } finally {
+ monitor.done();
+
+ }
+ }
+ });
+
+ } catch(InterruptedException ex) {
+ // ignore
+
+ } catch(InvocationTargetException ex) {
+ String msg = NLS.bind(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypePage_error_resolve2,
+ archetypeName);
+ MavenLogger.log(msg, ex);
+ setErrorMessage(msg + "\n" + ex.toString()); //$NON-NLS-1$
+
+ }
+ }
+
+ /**
+ * ArchetypeLabelProvider
+ */
+ protected static class ArchetypeLabelProvider extends LabelProvider implements ITableLabelProvider {
+ /** Returns the element text */
+ public String getColumnText(Object element, int columnIndex) {
+ if(element instanceof Archetype) {
+ Archetype archetype = (Archetype) element;
+ switch(columnIndex) {
+ case 0:
+ return archetype.getGroupId();
+ case 1:
+ return archetype.getArtifactId();
+ case 2:
+ return archetype.getVersion();
+ }
+ }
+ return super.getText(element);
+ }
+
+ /** Returns the element text */
+ public Image getColumnImage(Object element, int columnIndex) {
+ return null;
+ }
+ }
+
+ /**
+ * QuickViewerFilter
+ */
+ protected class QuickViewerFilter extends ViewerFilter implements ModifyListener {
+
+ private String currentFilter;
+
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if(currentFilter == null || currentFilter.length() == 0) {
+ return true;
+ }
+ Archetype archetype = (Archetype) element;
+ return archetype.getGroupId().indexOf(currentFilter) > -1
+ || archetype.getArtifactId().indexOf(currentFilter) > -1;
+ }
+
+ public void modifyText(ModifyEvent e) {
+ this.currentFilter = filterText.getText().trim();
+ viewer.refresh();
+ }
+ }
+
+ protected class IncludeSnapshotsFilter extends ViewerFilter implements SelectionListener {
+
+ /**
+ *
+ */
+ private static final String SNAPSHOT = "SNAPSHOT"; //$NON-NLS-1$
+
+ private boolean includeSnapshots = false;
+
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if(element instanceof Archetype) {
+ String version = ((Archetype) element).getVersion();
+ boolean isSnap = false;
+ if(M2EUtils.nullOrEmpty(version)) {
+ isSnap = false;
+ } else if(version.lastIndexOf(SNAPSHOT) >= 0) {
+ isSnap = true;
+ }
+ return includeSnapshots ? true : !isSnap;
+ }
+ return false;
+
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ this.includeSnapshots = includeShapshotsButton.getSelection();
+ viewer.refresh();
+ Archetype archetype = getArchetype();
+ //can be null in some cases, don't try to reveal
+ if(archetype != null) {
+ viewer.reveal(archetype);
+ }
+ viewer.getTable().setSelection(viewer.getTable().getSelectionIndex());
+ viewer.getTable().setFocus();
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ }
+
+ protected class LastVersionFilter extends ViewerFilter implements SelectionListener {
+
+ private boolean showLastVersion = true;
+
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ return showLastVersion ? lastVersionArchetypes.contains(element) : true;
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ this.showLastVersion = showLastVersionButton.getSelection();
+ viewer.refresh();
+ Archetype archetype = getArchetype();
+ //can be null in some cases, don't try to reveal
+ if(archetype != null) {
+ viewer.reveal(archetype);
+ }
+ viewer.getTable().setSelection(viewer.getTable().getSelectionIndex());
+ viewer.getTable().setFocus();
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.index.IndexListener#indexAdded(org.eclipse.m2e.repository.IRepository)
+ */
+ public void indexAdded(IRepository repository) {
+
+ }
+
+ //reload the table when index updating finishes
+ //try to preserve selection in case this is a rebuild
+ protected void reloadViewer() {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ if(isCurrentPage()) {
+ StructuredSelection sel = (StructuredSelection) viewer.getSelection();
+ Archetype selArchetype = null;
+ if(sel != null && sel.getFirstElement() != null) {
+ selArchetype = (Archetype) sel.getFirstElement();
+ }
+ if(selArchetype != null) {
+ loadArchetypes(selArchetype.getGroupId(), selArchetype.getArtifactId(), selArchetype.getVersion());
+ } else {
+ loadArchetypes("org.apache.maven.archetypes", "maven-archetype-quickstart", "1.0"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+ }
+ });
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.index.IndexListener#indexChanged(org.eclipse.m2e.repository.IRepository)
+ */
+ public void indexChanged(IRepository repository) {
+ reloadViewer();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.index.IndexListener#indexRemoved(org.eclipse.m2e.repository.IRepository)
+ */
+ public void indexRemoved(IRepository repository) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.m2e.index.IndexListener#indexUpdating(org.eclipse.m2e.repository.IRepository)
+ */
+ public void indexUpdating(IRepository repository) {
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArchetypeParametersPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArchetypeParametersPage.java
new file mode 100644
index 00000000..c566b6d4
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArchetypeParametersPage.java
@@ -0,0 +1,617 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import com.ibm.icu.lang.UCharacter;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+
+import org.apache.maven.archetype.catalog.Archetype;
+import org.apache.maven.archetype.common.ArchetypeArtifactManager;
+import org.apache.maven.archetype.exception.UnknownArchetype;
+import org.apache.maven.archetype.metadata.ArchetypeDescriptor;
+import org.apache.maven.archetype.metadata.RequiredProperty;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.model.Model;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+import org.eclipse.m2e.core.ui.internal.components.TextComboBoxCellEditor;
+
+
+/**
+ * Wizard page responsible for gathering information about the Maven2 artifact when an archetype is being used to create
+ * a project (thus the class name pun).
+ */
+public class MavenProjectWizardArchetypeParametersPage extends AbstractMavenWizardPage {
+
+ public static final String DEFAULT_VERSION = "0.0.1-SNAPSHOT"; //$NON-NLS-1$
+
+ public static final String DEFAULT_PACKAGE = "foo"; //$NON-NLS-1$
+
+ Table propertiesTable;
+
+ TableViewer propertiesViewer;
+
+ final public static String KEY_PROPERTY = "key"; //$NON-NLS-1$
+
+ final public static int KEY_INDEX = 0;
+
+ final public static String VALUE_PROPERTY = "value"; //$NON-NLS-1$
+
+ final public static int VALUE_INDEX = 1;
+
+ /** group id text field */
+ protected Combo groupIdCombo;
+
+ /** artifact id text field */
+ protected Combo artifactIdCombo;
+
+ /** version text field */
+ protected Combo versionCombo;
+
+ /** package text field */
+ protected Combo packageCombo;
+
+ protected Button removeButton;
+
+ private boolean isUsed = true;
+
+ protected Set<String> requiredProperties;
+
+ protected Set<String> optionalProperties;
+
+ protected Archetype archetype;
+
+ protected boolean archetypeChanged = false;
+
+ /** shows if the package has been customized by the user */
+ protected boolean packageCustomized = false;
+
+ /** Creates a new page. */
+ public MavenProjectWizardArchetypeParametersPage(ProjectImportConfiguration projectImportConfiguration) {
+ super("Maven2ProjectWizardArchifactPage", projectImportConfiguration); //$NON-NLS-1$
+
+ setTitle(Messages.getString("wizard.project.page.maven2.title")); //$NON-NLS-1$
+ setDescription(Messages.getString("wizard.project.page.maven2.archetype.parameters.description")); //$NON-NLS-1$
+ setPageComplete(false);
+
+ requiredProperties = new HashSet<String>();
+ optionalProperties = new HashSet<String>();
+ }
+
+ /** Creates page controls. */
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NULL);
+ composite.setLayout(new GridLayout(3, false));
+
+ createArtifactGroup(composite);
+ createPropertiesGroup(composite);
+
+ validate();
+
+ createAdvancedSettings(composite, new GridData(SWT.FILL, SWT.TOP, false, false, 3, 1));
+ resolverConfigurationComponent.setModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ validate();
+ }
+ });
+
+ setControl(composite);
+
+ }
+
+ private void createArtifactGroup(Composite parent) {
+// Composite artifactGroup = new Composite(parent, SWT.NONE);
+// GridData gd_artifactGroup = new GridData( SWT.FILL, SWT.FILL, true, false );
+// artifactGroup.setLayoutData(gd_artifactGroup);
+// artifactGroup.setLayout(new GridLayout(2, false));
+
+ Label groupIdlabel = new Label(parent, SWT.NONE);
+ groupIdlabel.setText(Messages.getString("artifactComponent.groupId")); //$NON-NLS-1$
+
+ groupIdCombo = new Combo(parent, SWT.BORDER);
+ groupIdCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ addFieldWithHistory("groupId", groupIdCombo); //$NON-NLS-1$
+ groupIdCombo.setData("name", "groupId"); //$NON-NLS-1$ //$NON-NLS-2$
+ groupIdCombo.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ updateJavaPackage();
+ validate();
+ }
+ });
+
+ Label artifactIdLabel = new Label(parent, SWT.NONE);
+ artifactIdLabel.setText(Messages.getString("artifactComponent.artifactId")); //$NON-NLS-1$
+
+ artifactIdCombo = new Combo(parent, SWT.BORDER);
+ artifactIdCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
+ addFieldWithHistory("artifactId", artifactIdCombo); //$NON-NLS-1$
+ artifactIdCombo.setData("name", "artifactId"); //$NON-NLS-1$ //$NON-NLS-2$
+ artifactIdCombo.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ updateJavaPackage();
+ validate();
+ }
+ });
+
+ Label versionLabel = new Label(parent, SWT.NONE);
+ versionLabel.setText(Messages.getString("artifactComponent.version")); //$NON-NLS-1$
+
+ versionCombo = new Combo(parent, SWT.BORDER);
+ GridData gd_versionCombo = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
+ gd_versionCombo.widthHint = 150;
+ versionCombo.setLayoutData(gd_versionCombo);
+ versionCombo.setText(DEFAULT_VERSION);
+ addFieldWithHistory("version", versionCombo); //$NON-NLS-1$
+ versionCombo.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ validate();
+ }
+ });
+
+ Label packageLabel = new Label(parent, SWT.NONE);
+ packageLabel.setText(Messages.getString("artifactComponent.package")); //$NON-NLS-1$
+
+ packageCombo = new Combo(parent, SWT.BORDER);
+ packageCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
+ packageCombo.setData("name", "package"); //$NON-NLS-1$ //$NON-NLS-2$
+ addFieldWithHistory("package", packageCombo); //$NON-NLS-1$
+ packageCombo.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ if(!packageCustomized && !packageCombo.getText().equals(getDefaultJavaPackage())) {
+ packageCustomized = true;
+ }
+ validate();
+ }
+ });
+ }
+
+ private void createPropertiesGroup(Composite composite) {
+ Label propertiesLabel = new Label(composite, SWT.NONE);
+ propertiesLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+ propertiesLabel.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypeParametersPage_lblProps);
+
+ propertiesViewer = new TableViewer(composite, SWT.BORDER | SWT.FULL_SELECTION);
+ propertiesTable = propertiesViewer.getTable();
+ propertiesTable.setLinesVisible(true);
+ propertiesTable.setHeaderVisible(true);
+ propertiesTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 2));
+
+ TableColumn propertiesTableNameColumn = new TableColumn(propertiesTable, SWT.NONE);
+ propertiesTableNameColumn.setWidth(130);
+ propertiesTableNameColumn.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypeParametersPage_columnName);
+
+ TableColumn propertiesTableValueColumn = new TableColumn(propertiesTable, SWT.NONE);
+ propertiesTableValueColumn.setWidth(230);
+ propertiesTableValueColumn.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypeParametersPage_columnValue);
+
+ propertiesViewer.setColumnProperties(new String[] {KEY_PROPERTY, VALUE_PROPERTY});
+
+ propertiesViewer.setCellEditors(new CellEditor[] {new TextCellEditor(propertiesTable, SWT.NONE),
+ new TextCellEditor(propertiesTable, SWT.NONE)});
+ propertiesViewer.setCellModifier(new ICellModifier() {
+ public boolean canModify(Object element, String property) {
+ return true;
+ }
+
+ public void modify(Object element, String property, Object value) {
+ if(element instanceof TableItem) {
+ ((TableItem) element).setText(getTextIndex(property), String.valueOf(value));
+ validate();
+ }
+ }
+
+ public Object getValue(Object element, String property) {
+ if(element instanceof TableItem) {
+ return ((TableItem) element).getText(getTextIndex(property));
+ }
+ return null;
+ }
+ });
+
+ Button addButton = new Button(composite, SWT.NONE);
+ addButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ addButton.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypeParametersPage_btnAdd);
+ addButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ propertiesViewer.editElement(addTableItem("?", "?"), KEY_INDEX); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ });
+
+ removeButton = new Button(composite, SWT.NONE);
+ removeButton.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
+ removeButton.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypeParametersPage_btnRemove);
+ removeButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ if(propertiesTable.getSelectionCount() > 0) {
+ propertiesTable.remove(propertiesTable.getSelectionIndices());
+ removeButton.setEnabled(propertiesTable.getItemCount() > 0);
+ validate();
+ }
+ }
+ });
+ }
+
+ /**
+ * Validates the contents of this wizard page.
+ * <p>
+ * Feedback about the validation is given to the user by displaying error messages or informative messages on the
+ * wizard page. Depending on the provided user input, the wizard page is marked as being complete or not.
+ * <p>
+ * If some error or missing input is detected in the user input, an error message or informative message,
+ * respectively, is displayed to the user. If the user input is complete and correct, the wizard page is marked as
+ * begin complete to allow the wizard to proceed. To that end, the following conditions must be met:
+ * <ul>
+ * <li>The user must have provided a valid group ID.</li>
+ * <li>The user must have provided a valid artifact ID.</li>
+ * <li>The user must have provided a version for the artifact.</li>
+ * </ul>
+ * </p>
+ *
+ * @see org.eclipse.jface.dialogs.DialogPage#setMessage(java.lang.String)
+ * @see org.eclipse.jface.wizard.WizardPage#setErrorMessage(java.lang.String)
+ * @see org.eclipse.jface.wizard.WizardPage#setPageComplete(boolean)
+ */
+ void validate() {
+ String error = validateInput();
+ setErrorMessage(error);
+ setPageComplete(error == null);
+ }
+
+ private String validateInput() {
+ String error = validateIdInput(groupIdCombo.getText().trim(), "group"); //$NON-NLS-1$
+ if(error != null) {
+ return error;
+ }
+
+ error = validateIdInput(artifactIdCombo.getText().trim(), "artifact"); //$NON-NLS-1$
+ if(error != null) {
+ return error;
+ }
+
+ String versionValue = versionCombo.getText().trim();
+ if(versionValue.length() == 0) {
+ return Messages.getString("wizard.project.page.maven2.validator.version"); //$NON-NLS-1$
+ }
+ //TODO: check validity of version?
+
+ String packageName = packageCombo.getText();
+ if(packageName.trim().length() != 0) {
+ if(!Pattern.matches("[A-Za-z_$][A-Za-z_$\\d]*(?:\\.[A-Za-z_$][A-Za-z_$\\d]*)*", packageName)) { //$NON-NLS-1$
+ return org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypeParametersPage_error_package;
+ }
+ }
+
+ // validate project name
+ IStatus nameStatus = getImportConfiguration().validateProjectName(getModel());
+ if(!nameStatus.isOK()) {
+ return Messages.getString("wizard.project.page.maven2.validator.projectNameInvalid", nameStatus.getMessage()); //$NON-NLS-1$
+ }
+
+ if(requiredProperties.size() > 0) {
+ Properties properties = getProperties();
+ for(String key : requiredProperties) {
+ String value = properties.getProperty(key);
+ if(value == null || value.length() == 0) {
+ return Messages.getString("wizard.project.page.maven2.validator.requiredProperty", key); //$NON-NLS-1$
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /** Ends the wizard flow chain. */
+ public IWizardPage getNextPage() {
+ return null;
+ }
+
+ public void setArchetype(Archetype archetype) {
+ if(archetype == null) {
+ propertiesTable.removeAll();
+ archetypeChanged = false;
+ } else if(!archetype.equals(this.archetype)) {
+ this.archetype = archetype;
+ propertiesTable.removeAll();
+ requiredProperties.clear();
+ optionalProperties.clear();
+ archetypeChanged = true;
+
+ Properties properties = archetype.getProperties();
+ if(properties != null) {
+ for(Iterator<Map.Entry<Object, Object>> it = properties.entrySet().iterator(); it.hasNext();) {
+ Map.Entry<?, ?> e = it.next();
+ String key = (String) e.getKey();
+ addTableItem(key, (String) e.getValue());
+ optionalProperties.add(key);
+ }
+ }
+ }
+ }
+
+ void loadArchetypeDescriptor() {
+ final String groupId = archetype.getGroupId();
+ final String artifactId = archetype.getArtifactId();
+ final String version = archetype.getVersion();
+ final String archetypeName = groupId + ":" + artifactId + ":" + version; //$NON-NLS-1$ //$NON-NLS-2$
+
+ try {
+ getContainer().run(false, true, new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor) {
+ monitor.beginTask(NLS.bind(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypeParametersPage_task, archetypeName), IProgressMonitor.UNKNOWN);
+ try {
+ IMaven maven = MavenPlugin.getDefault().getMaven();
+
+ ArtifactRepository localRepository = maven.getLocalRepository();
+
+ List<ArtifactRepository> repositories = maven.getArtifactRepositories();
+
+ ArchetypeArtifactManager aaMgr = MavenPlugin.getDefault().getArchetypeArtifactManager();
+ if(aaMgr.isFileSetArchetype(groupId, artifactId, version, null, localRepository, repositories)) {
+ ArchetypeDescriptor descriptor = aaMgr.getFileSetArchetypeDescriptor(groupId, artifactId, version, null,
+ localRepository, repositories);
+ List<?> properties = descriptor.getRequiredProperties();
+ if(properties != null) {
+ for(Object o : properties) {
+ if(o instanceof RequiredProperty) {
+ RequiredProperty rp = (RequiredProperty) o;
+ requiredProperties.add(rp.getKey());
+ addTableItem(rp.getKey(), rp.getDefaultValue());
+ }
+ }
+ }
+ }
+ } catch(UnknownArchetype e) {
+ MavenLogger.log(NLS.bind("Error downloading archetype {0}",archetypeName), e);
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ } finally {
+ monitor.done();
+ }
+ }
+ });
+ } catch(InterruptedException ex) {
+ // ignore
+ } catch(InvocationTargetException ex) {
+ String msg = NLS.bind(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArchetypeParametersPage_error_download, archetypeName);
+ MavenLogger.log(msg, ex);
+ setErrorMessage(msg + "\n" + ex.toString()); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * @param key
+ * @param value
+ */
+ TableItem addTableItem(String key, String value) {
+ TableItem item = new TableItem(propertiesTable, SWT.NONE);
+ item.setData(item);
+ item.setText(KEY_INDEX, key);
+ item.setText(VALUE_INDEX, value == null ? "" : value); //$NON-NLS-1$
+ return item;
+ }
+
+ /**
+ * Updates the properties when a project name is set on the first page of the wizard.
+ */
+ public void setProjectName(String projectName) {
+ if(artifactIdCombo.getText().equals(groupIdCombo.getText())) {
+ groupIdCombo.setText(projectName);
+ }
+ artifactIdCombo.setText(projectName);
+ packageCombo.setText("org." + projectName.replace('-', '.')); //$NON-NLS-1$
+ validate();
+ }
+
+ /**
+ * Updates the properties when a project name is set on the first page of the wizard.
+ */
+ public void setParentProject(String groupId, String artifactId, String version) {
+ groupIdCombo.setText(groupId);
+ versionCombo.setText(version);
+ validate();
+ }
+
+ /** Enables or disables the artifact id text field. */
+ public void setArtifactIdEnabled(boolean b) {
+ artifactIdCombo.setEnabled(b);
+ }
+
+ /** Returns the package name. */
+ public String getJavaPackage() {
+ if(packageCombo.getText().length() > 0) {
+ return packageCombo.getText();
+ }
+ return getDefaultJavaPackage();
+ }
+
+ /** Updates the package name if the related fields changed. */
+ protected void updateJavaPackage() {
+ if(packageCustomized) {
+ return;
+ }
+
+ String defaultPackageName = getDefaultJavaPackage();
+ packageCombo.setText(defaultPackageName);
+ }
+
+ /** Returns the default package name. */
+ protected String getDefaultJavaPackage() {
+ return MavenProjectWizardArchetypeParametersPage.getDefaultJavaPackage(groupIdCombo.getText().trim(),
+ artifactIdCombo.getText().trim());
+ }
+
+ /** Creates the Model object. */
+ public Model getModel() {
+ Model model = new Model();
+
+ model.setModelVersion("4.0.0"); //$NON-NLS-1$
+ model.setGroupId(groupIdCombo.getText());
+ model.setArtifactId(artifactIdCombo.getText());
+ model.setVersion(versionCombo.getText());
+
+ return model;
+ }
+
+ public void setUsed(boolean isUsed) {
+ this.isUsed = isUsed;
+ }
+
+ public boolean isPageComplete() {
+ return !isUsed || super.isPageComplete();
+ }
+
+ /** Loads the group value when the page is displayed. */
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+
+ if(visible) {
+ if(groupIdCombo.getText().length() == 0 && groupIdCombo.getItemCount() > 0) {
+ groupIdCombo.setText(groupIdCombo.getItem(0));
+ packageCombo.setText(getDefaultJavaPackage());
+ packageCustomized = false;
+ }
+
+ if(archetypeChanged && archetype != null) {
+ archetypeChanged = false;
+ loadArchetypeDescriptor();
+ validate();
+ }
+
+ updatePropertyEditors();
+ }
+ }
+
+ public Properties getProperties() {
+ if(propertiesViewer.isCellEditorActive()) {
+ propertiesTable.setFocus();
+ }
+ Properties properties = new Properties();
+ for(int i = 0; i < propertiesTable.getItemCount(); i++ ) {
+ TableItem item = propertiesTable.getItem(i);
+ properties.put(item.getText(KEY_INDEX), item.getText(VALUE_INDEX));
+ }
+ return properties;
+ }
+
+ public int getTextIndex(String property) {
+ return KEY_PROPERTY.equals(property) ? KEY_INDEX : VALUE_INDEX;
+ }
+
+ public void updatePropertyEditors() {
+ CellEditor[] ce = propertiesViewer.getCellEditors();
+
+ int n = requiredProperties.size() + optionalProperties.size();
+ if(n == 0) {
+ if(ce[KEY_INDEX] instanceof TextComboBoxCellEditor) {
+ // if there was a combo editor previously defined, and the current
+ // archetype has no properties, replace it with a plain text editor
+ ce[KEY_INDEX].dispose();
+ ce[KEY_INDEX] = new TextCellEditor(propertiesTable, SWT.FLAT);
+ }
+ } else {
+ TextComboBoxCellEditor comboEditor = null;
+ // if there was a plain text editor previously defined, and the current
+ // archetype has properties, replace it with a combo editor
+ if(ce[KEY_INDEX] instanceof TextComboBoxCellEditor) {
+ comboEditor = (TextComboBoxCellEditor) ce[KEY_INDEX];
+ } else {
+ ce[KEY_INDEX].dispose();
+ comboEditor = new TextComboBoxCellEditor(propertiesTable, SWT.FLAT);
+ ce[KEY_INDEX] = comboEditor;
+ }
+
+ // populate the property name selection
+ List<String> propertyKeys = new ArrayList<String>(n);
+ propertyKeys.addAll(requiredProperties);
+ propertyKeys.addAll(optionalProperties);
+ comboEditor.setItems(propertyKeys.toArray(new String[n]));
+ }
+ }
+
+ public static String getDefaultJavaPackage(String groupId, String artifactId) {
+ StringBuffer sb = new StringBuffer(groupId);
+
+ if(sb.length() > 0 && artifactId.length() > 0) {
+ sb.append('.');
+ }
+
+ sb.append(artifactId);
+
+ if(sb.length() == 0) {
+ sb.append(DEFAULT_PACKAGE);
+ }
+
+ boolean isFirst = true;
+ StringBuffer pkg = new StringBuffer();
+ for(int i = 0; i < sb.length(); i++ ) {
+ char c = sb.charAt(i);
+ if(c == '-') {
+ pkg.append('_');
+ isFirst = false;
+ } else {
+ if(isFirst) {
+ if(UCharacter.isJavaIdentifierStart(c)) {
+ pkg.append(c);
+ isFirst = false;
+ }
+ } else {
+ if(c == '.') {
+ pkg.append('.');
+ isFirst = true;
+ } else if(UCharacter.isJavaIdentifierPart(c)) {
+ pkg.append(c);
+ }
+ }
+ }
+ }
+
+ return pkg.toString();
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArtifactPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArtifactPage.java
new file mode 100644
index 00000000..aabcc22d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardArtifactPage.java
@@ -0,0 +1,364 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+
+import org.apache.maven.model.Model;
+
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+import org.eclipse.m2e.core.ui.dialogs.MavenRepositorySearchDialog;
+
+
+/**
+ * Wizard page responsible for gathering information about the Maven2 artifact and the directories to create. This
+ * wizard page gathers Maven2 specific information. The user must specify the necessary information about the Maven2
+ * artifact and she can also decide which directories of the default Maven2 directory structure should be created. Input
+ * validation is performed in order to make sure that all the provided information is valid before letting the wizard
+ * continue.
+ */
+public class MavenProjectWizardArtifactPage extends AbstractMavenWizardPage {
+
+ private static final ProjectFolder JAVA = new ProjectFolder("src/main/java", "target/classes"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ private static final ProjectFolder JAVA_TEST = new ProjectFolder("src/test/java", "target/test-classes"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ private static final ProjectFolder RESOURCES = new ProjectFolder("src/main/resources", "target/classes"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ private static final ProjectFolder RESOURCES_TEST = new ProjectFolder("src/test/resources", "target/test-classes"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ // private static final ProjectFolder FILTERS = new ProjectFolder("src/main/filters", null, false);
+
+ // private static final ProjectFolder FILTERS_TEST = new ProjectFolder("src/test/filters", null, false);
+
+ // private static final ProjectFolder ASSEMBLY = new ProjectFolder("src/main/assembly", null, false);
+
+ // private static final ProjectFolder CONFIG = new ProjectFolder("src/main/config", null, false);
+
+ private static final ProjectFolder WEBAPP = new ProjectFolder("src/main/webapp", null); //$NON-NLS-1$
+
+ private static final ProjectFolder EAR = new ProjectFolder("src/main/application", null); //$NON-NLS-1$
+
+ private static final ProjectFolder SITE = new ProjectFolder("src/site", null); //$NON-NLS-1$
+
+ private static final ProjectFolder[] JAR_DIRS = {JAVA, JAVA_TEST, RESOURCES, RESOURCES_TEST};
+
+ private static final ProjectFolder[] WAR_DIRS = {JAVA, JAVA_TEST, RESOURCES, RESOURCES_TEST, WEBAPP};
+
+ private static final ProjectFolder[] EAR_DIRS = {EAR}; // MNGECLIPSE-688 add EAR Support
+
+ private static final ProjectFolder[] POM_DIRS = {SITE};
+
+ /** special directory sets, default is JAR_DIRS */
+ private static final Map<String, ProjectFolder[]> directorySets = new HashMap<String, ProjectFolder[]>();
+ static {
+ directorySets.put(MavenArtifactComponent.WAR, WAR_DIRS);
+ directorySets.put(MavenArtifactComponent.POM, POM_DIRS);
+ directorySets.put(MavenArtifactComponent.EAR, EAR_DIRS); // MNGECLIPSE-688 add EAR Support
+ }
+
+ /** parent property panel */
+ protected MavenParentComponent parentComponent;
+
+ /** artifact property panel */
+ protected MavenArtifactComponent artifactComponent;
+
+ /** the parent readonly state */
+ private boolean readonlyParent = false;
+
+ private boolean isUsed;
+
+ /**
+ * Sets the title and description of this wizard page and marks it as not being complete as user input is required for
+ * continuing.
+ * @wbp.parser.constructor
+ */
+ public MavenProjectWizardArtifactPage(ProjectImportConfiguration projectImportConfiguration) {
+ this("MavenProjectWizardArtifactPage", projectImportConfiguration); //$NON-NLS-1$
+ }
+
+ /**
+ * Sets the title and description of this wizard page and marks it as not being complete as user input is required for
+ * continuing.
+ */
+ protected MavenProjectWizardArtifactPage(String name, ProjectImportConfiguration projectImportConfiguration) {
+ super(name, projectImportConfiguration);
+
+ setTitle(Messages.getString("wizard.project.page.maven2.title")); //$NON-NLS-1$
+ setDescription(Messages.getString("wizard.project.page.maven2.description")); //$NON-NLS-1$
+ setPageComplete(false);
+ }
+
+ /**
+ * {@inheritDoc} This wizard page contains a <code>MavenArtifactComponent</code> to gather information about the Maven
+ * artifact and a <code>Maven2DirectoriesComponent</code> which allows to choose which directories of the default
+ * Maven directory structure to create.
+ */
+ public void createControl(Composite parent) {
+ GridLayout layout = new GridLayout();
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+
+ Composite container = new Composite(parent, SWT.NULL);
+ container.setLayout(layout);
+
+ WidthGroup widthGroup = new WidthGroup();
+ container.addControlListener(widthGroup);
+
+ ModifyListener modifyingListener = new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ validate();
+ }
+ };
+
+ artifactComponent = new MavenArtifactComponent(container, SWT.NONE);
+ artifactComponent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ artifactComponent.setWidthGroup(widthGroup);
+ artifactComponent.setModifyingListener(modifyingListener);
+ artifactComponent.setArtifactIdEditable(!readonlyParent);
+
+ parentComponent = new MavenParentComponent(container, readonlyParent ? SWT.READ_ONLY : SWT.NONE);
+ parentComponent.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ parentComponent.setWidthGroup(widthGroup);
+
+ parentComponent.addModifyListener(modifyingListener);
+ parentComponent.addBrowseButtonListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ MavenRepositorySearchDialog dialog = new MavenRepositorySearchDialog(getShell(), //
+ org.eclipse.m2e.core.internal.Messages.MavenProjectWizardArtifactPage_searchDialog_title, IIndex.SEARCH_PARENTS, Collections.<ArtifactKey> emptySet(), false);
+
+ if(dialog.open() == Window.OK) {
+ IndexedArtifactFile indexedArtifactFile = (IndexedArtifactFile) dialog.getFirstResult();
+ if(indexedArtifactFile != null) {
+ parentComponent.setValues(indexedArtifactFile.group, indexedArtifactFile.artifact,
+ indexedArtifactFile.version);
+ }
+ }
+ }
+ });
+
+ createAdvancedSettings(container, new GridData(SWT.FILL, SWT.TOP, false, false, 2, 1));
+ resolverConfigurationComponent.setModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ validate();
+ }
+ });
+
+ addFieldWithHistory("groupId", artifactComponent.getGroupIdCombo()); //$NON-NLS-1$
+ addFieldWithHistory("artifactId", artifactComponent.getArtifactIdCombo()); //$NON-NLS-1$
+ addFieldWithHistory("version", artifactComponent.getVersionCombo()); //$NON-NLS-1$
+ addFieldWithHistory("name", artifactComponent.getNameCombo()); //$NON-NLS-1$
+
+ addFieldWithHistory("groupId", parentComponent.getGroupIdCombo()); //$NON-NLS-1$
+ addFieldWithHistory("artifactId", parentComponent.getArtifactIdCombo()); //$NON-NLS-1$
+ addFieldWithHistory("version", parentComponent.getVersionCombo()); //$NON-NLS-1$
+
+ container.layout();
+
+ validate();
+
+ setControl(container);
+ }
+
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ artifactComponent.getGroupIdCombo().setFocus();
+ }
+
+ /**
+ * Returns the Maven2 model containing the artifact information provided by the user.
+ *
+ * @return The Maven2 model containing the provided artifact information. Is never <code>null</code>.
+ */
+ public Model getModel() {
+ Model model = artifactComponent.getModel();
+
+ parentComponent.updateModel(model);
+
+ return model;
+ }
+
+ /** Returns the list of directories for the currently selected packaging. */
+ private ProjectFolder[] getProjectFolders() {
+ ProjectFolder[] folders = directorySets.get(artifactComponent.getPackaging());
+ return folders == null ? JAR_DIRS : folders;
+ }
+
+ /**
+ * Returns the directories of the default Maven2 directory structure selected by the user. These directories should be
+ * created along with the new project.
+ *
+ * @return The Maven2 directories selected by the user. Neither the array nor any of its elements is <code>null</code>
+ * .
+ */
+ public String[] getFolders() {
+ ProjectFolder[] mavenDirectories = getProjectFolders();
+
+ String[] directories = new String[mavenDirectories.length];
+ for(int i = 0; i < directories.length; i++ ) {
+ directories[i] = mavenDirectories[i].getPath();
+ }
+
+ return directories;
+ }
+
+ /**
+ * Validates the contents of this wizard page.
+ * <p>
+ * Feedback about the validation is given to the user by displaying error messages or informative messages on the
+ * wizard page. Depending on the provided user input, the wizard page is marked as being complete or not.
+ * <p>
+ * If some error or missing input is detected in the user input, an error message or informative message,
+ * respectively, is displayed to the user. If the user input is complete and correct, the wizard page is marked as
+ * begin complete to allow the wizard to proceed. To that end, the following conditions must be met:
+ * <ul>
+ * <li>The user must have provided a group ID.</li>
+ * <li>The user must have provided an artifact ID.</li>
+ * <li>The user must have provided a version for the artifact.</li>
+ * <li>The user must have provided the packaging type for the artifact.</li>
+ * </ul>
+ * </p>
+ *
+ * @see org.eclipse.jface.dialogs.DialogPage#setMessage(java.lang.String)
+ * @see org.eclipse.jface.wizard.WizardPage#setErrorMessage(java.lang.String)
+ * @see org.eclipse.jface.wizard.WizardPage#setPageComplete(boolean)
+ */
+ void validate() {
+ String error = validateInput();
+ setErrorMessage(error);
+ setPageComplete(error == null);
+ }
+
+ private String validateInput() {
+ String error = validateIdInput(artifactComponent.getGroupId().trim(), "group"); //$NON-NLS-1$
+ if(error != null) {
+ return error;
+ }
+
+ error = validateIdInput(artifactComponent.getArtifactId().trim(), "artifact"); //$NON-NLS-1$
+ if(error != null) {
+ return error;
+ }
+
+ if(artifactComponent.getVersion().trim().length() == 0) {
+ return Messages.getString("wizard.project.page.maven2.validator.version"); //$NON-NLS-1$
+ }
+
+ if(artifactComponent.getPackaging().trim().length() == 0) {
+ return Messages.getString("wizard.project.page.maven2.validator.packaging"); //$NON-NLS-1$
+ }
+
+ // if the parent project is specified, all three fields must be present
+ if(!parentComponent.validate()) {
+ return Messages.getString("wizard.project.page.maven2.validator.parent"); //$NON-NLS-1$
+ }
+
+ // validate project name
+ IStatus nameStatus = getImportConfiguration().validateProjectName(artifactComponent.getModel());
+ if(!nameStatus.isOK()) {
+ return nameStatus.getMessage();
+ }
+
+ return null;
+ }
+
+ /**
+ * Updates the properties when a project name is set on the first page of the wizard.
+ */
+ public void setProjectName(String projectName) {
+ if(artifactComponent.getArtifactId().equals(artifactComponent.getGroupId())) {
+ artifactComponent.setGroupId(projectName);
+ }
+ artifactComponent.setArtifactId(projectName);
+ validate();
+ }
+
+ /** Sets the readonly parent flag. */
+ public void setParentReadonly(boolean b) {
+ readonlyParent = b;
+ }
+
+ /**
+ * Updates the properties when a project name is set on the first page of the wizard.
+ */
+ public void setParentProject(String groupId, String artifactId, String version) {
+ parentComponent.setValues(groupId, artifactId, version);
+ artifactComponent.setGroupId(groupId);
+ artifactComponent.setVersion(version);
+ validate();
+ }
+
+ public void setUsed(boolean isUsed) {
+ this.isUsed = isUsed;
+ }
+
+ public boolean isPageComplete() {
+ return !isUsed || super.isPageComplete();
+ }
+
+ /**
+ * A placeholder representing a directory in the project structure.
+ */
+ final static class ProjectFolder {
+
+ /** Folder path */
+ private String path = null;
+
+ /** Output path */
+ private String outputPath = null;
+
+ ProjectFolder(String path, String outputPath) {
+ this.path = path;
+ this.outputPath = outputPath;
+ }
+
+ /**
+ * Returns folder path
+ */
+ String getPath() {
+ return path;
+ }
+
+ /**
+ * Returns folder output path
+ */
+ String getOutputPath() {
+ return outputPath;
+ }
+
+ /**
+ * Returns true for source folder
+ */
+ boolean isSourceEntry() {
+ return this.getOutputPath() != null;
+ }
+
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardLocationPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardLocationPage.java
new file mode 100644
index 00000000..78f91edc
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/MavenProjectWizardLocationPage.java
@@ -0,0 +1,321 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Label;
+
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+
+
+/**
+ * Wizard page used to specify project location and working set.
+ */
+public class MavenProjectWizardLocationPage extends AbstractMavenWizardPage {
+
+ Button useDefaultWorkspaceLocationButton;
+ Label locationLabel;
+ Combo locationCombo;
+
+ boolean initialized = false;
+ private WorkingSetGroup workingSetGroup;
+
+ private IPath location;
+
+ /**
+ * Creates Maven project location page.
+ *
+ * @param title location page title text
+ * @param description location page description text
+ */
+ public MavenProjectWizardLocationPage(ProjectImportConfiguration configuration, String title, String description) {
+ super("MavenProjectWizardLocationPage", configuration); //$NON-NLS-1$
+ setTitle(title);
+ setDescription(description);
+ setPageComplete(false);
+
+ }
+
+ /**
+ * Creates Maven project location page.
+ */
+ public MavenProjectWizardLocationPage(ProjectImportConfiguration configuration, boolean showSimpleProject) {
+ super("MavenProjectWizardLocationPage", configuration); //$NON-NLS-1$
+ setTitle(Messages.getString("wizard.project.page.project.title")); //$NON-NLS-1$
+ setDescription(Messages.getString("wizard.project.page.project.description")); //$NON-NLS-1$
+ setPageComplete(false);
+ }
+
+ /**
+ * {@inheritDoc} This wizard page contains a component to query the project name and a
+ * <code>MavenLocationComponent</code> which allows to specify whether the project should be created in the
+ * workspace or at some given external location.
+ */
+ public void createControl(Composite parent) {
+ Composite container = new Composite(parent, SWT.NULL);
+ container.setLayout(new GridLayout(3, false));
+
+ createAdditionalControls(container);
+
+// // project name
+// GridData gridData = new GridData();
+// Label label = new Label(container, SWT.NULL);
+// label.setLayoutData(gridData);
+// label.setText(Messages.getString("wizard.project.page.project.projectName"));
+// projectNameText = new Combo(container, SWT.BORDER | SWT.SINGLE);
+// projectNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+// projectNameText.addModifyListener(modifyingListener);
+// addFieldWithHistory("projectName", projectNameText);
+
+ // gridData.verticalIndent = 5;
+// locationComponent = new MavenLocationComponent(container, SWT.NONE);
+// locationComponent.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 3, 1));
+// locationComponent.setModifyingListener(modifyingListener);
+// addFieldWithHistory("location", locationComponent.getLocationCombo());
+
+ useDefaultWorkspaceLocationButton = new Button(container, SWT.CHECK);
+ GridData useDefaultWorkspaceLocationButtonData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1);
+ useDefaultWorkspaceLocationButton.setLayoutData(useDefaultWorkspaceLocationButtonData);
+ useDefaultWorkspaceLocationButton.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardLocationPage_btnUserDefault);
+ useDefaultWorkspaceLocationButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ boolean inWorkspace = isInWorkspace();
+ locationLabel.setEnabled(!inWorkspace);
+ locationCombo.setEnabled(!inWorkspace);
+ }
+ });
+ useDefaultWorkspaceLocationButton.setSelection(true);
+
+ locationLabel = new Label(container, SWT.NONE);
+ GridData locationLabelData = new GridData();
+ locationLabelData.horizontalIndent = 10;
+ locationLabel.setLayoutData(locationLabelData);
+ locationLabel.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardLocationPage_lblLocation);
+ locationLabel.setEnabled(false);
+
+ locationCombo = new Combo(container, SWT.NONE);
+ GridData locationComboData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+ locationCombo.setLayoutData(locationComboData);
+ locationCombo.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ validate();
+ }
+ });
+ locationCombo.setEnabled(false);
+ addFieldWithHistory("location", locationCombo); //$NON-NLS-1$
+
+ Button locationBrowseButton = new Button(container, SWT.NONE);
+ GridData locationBrowseButtonData = new GridData(SWT.FILL, SWT.CENTER, false, false);
+ locationBrowseButton.setLayoutData(locationBrowseButtonData);
+ locationBrowseButton.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardLocationPage_btnLocation);
+ locationBrowseButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ DirectoryDialog dialog = new DirectoryDialog(getShell());
+ dialog.setText(org.eclipse.m2e.core.internal.Messages.MavenProjectWizardLocationPage_dialog_location);
+
+ String path = locationCombo.getText();
+ if(path.length()==0) {
+ path = ResourcesPlugin.getWorkspace().getRoot().getLocation().toPortableString();
+ }
+ dialog.setFilterPath(path);
+
+ String selectedDir = dialog.open();
+ if(selectedDir != null) {
+ locationCombo.setText(selectedDir);
+ useDefaultWorkspaceLocationButton.setSelection(false);
+ validate();
+ }
+ }
+ });
+
+ this.workingSetGroup = new WorkingSetGroup(container, getImportConfiguration(), getShell());
+
+ if(location==null || Platform.getLocation().equals(location)) {
+// useDefaultWorkspaceLocationButton.setSelection(true);
+ } else {
+// useDefaultWorkspaceLocationButton.setSelection(false);
+// locationLabel.setEnabled(true);
+// locationCombo.setEnabled(true);
+ locationCombo.setText(location.toOSString());
+ }
+
+ createAdvancedSettings(container, new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1));
+
+ setControl(container);
+ }
+
+ /**
+ * Create additional controls
+ */
+ protected void createAdditionalControls(Composite container) {
+ }
+
+ public void dispose() {
+ super.dispose();
+ workingSetGroup.dispose();
+ }
+
+ /**
+ * Returns whether the user has chosen to create the project in the workspace or at an external location.
+ *
+ * @return <code>true</code> if the project is to be created in the workspace, <code>false</code> if it should be
+ * created at an external location.
+ */
+ public boolean isInWorkspace() {
+ return useDefaultWorkspaceLocationButton.getSelection();
+ }
+
+ /**
+ * Returns the path of the location where the project is to be created. According to the user input, the path either
+ * points to the workspace or to a valid user specified location on the filesystem.
+ *
+ * @return The path of the location where to create the project. Is never <code>null</code>.
+ */
+ public IPath getLocationPath() {
+ if(isInWorkspace()) {
+ return ResourcesPlugin.getWorkspace().getRoot().getLocation();
+ }
+ return Path.fromOSString(locationCombo.getText().trim());
+ }
+
+ public void setLocationPath(IPath location) {
+ this.location = location;
+ }
+
+ /** {@inheritDoc} */
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+
+ if(visible) {
+ initialized = true;
+ validate();
+// projectNameText.setFocus();
+ }
+ }
+
+ /**
+ * Validates the contents of this wizard page.
+ * <p>
+ * Feedback about the validation is given to the user by displaying error messages or informative messages on the
+ * wizard page. Depending on the provided user input, the wizard page is marked as being complete or not.
+ * <p>
+ * If some error or missing input is detected in the user input, an error message or informative message,
+ * respectively, is displayed to the user. If the user input is complete and correct, the wizard page is marked as
+ * begin complete to allow the wizard to proceed. To that end, the following conditions must be met:
+ * <ul>
+ * <li>The user must have provided a project name.</li>
+ * <li>The project name must be a valid project resource identifier.</li>
+ * <li>A project with the same name must not exist.</li>
+ * <li>A valid project location path must have been specified.</li>
+ * </ul>
+ * </p>
+ *
+ * @see org.eclipse.core.resources.IWorkspace#validateName(java.lang.String, int)
+ * @see org.eclipse.core.resources.IWorkspace#validateProjectLocation(org.eclipse.core.resources.IProject,
+ * org.eclipse.core.runtime.IPath)
+ * @see org.eclipse.jface.dialogs.DialogPage#setMessage(java.lang.String)
+ * @see org.eclipse.jface.wizard.WizardPage#setErrorMessage(java.lang.String)
+ * @see org.eclipse.jface.wizard.WizardPage#setPageComplete(boolean)
+ */
+ protected void validate() {
+ if (!initialized) {
+ return;
+ }
+
+ final IWorkspace workspace = ResourcesPlugin.getWorkspace();
+
+// final String name = getProjectName();
+//
+// // check whether the project name field is empty
+// if(name.trim().length() == 0) {
+// setErrorMessage(null);
+// setMessage(Messages.getString("wizard.project.page.project.validator.projectName"));
+// setPageComplete(false);
+// return;
+// }
+//
+// // check whether the project name is valid
+// final IStatus nameStatus = workspace.validateName(name, IResource.PROJECT);
+// if(!nameStatus.isOK()) {
+// setErrorMessage(nameStatus.getMessage());
+// setPageComplete(false);
+// return;
+// }
+//
+// // check whether project already exists
+// final IProject handle = getProjectHandle();
+// if(handle.exists()) {
+// setErrorMessage(Messages.getString("wizard.project.page.project.validator.projectExists"));
+// setPageComplete(false);
+// return;
+// }
+
+ IPath projectPath = getLocationPath();
+ String location = projectPath.toOSString();
+
+ // check whether location is empty
+ if(location.length() == 0) {
+ setErrorMessage(null);
+ setMessage(Messages.getString("wizard.project.page.project.validator.projectLocation")); //$NON-NLS-1$
+ setPageComplete(false);
+ return;
+ }
+
+ // check whether the location is a syntactically correct path
+ if(!Path.ROOT.isValidPath(location)) {
+ setErrorMessage(Messages.getString("wizard.project.page.project.validator.invalidLocation")); //$NON-NLS-1$
+ setPageComplete(false);
+ return;
+ }
+
+ // If we do not place the contents in the workspace validate the location.
+ if(!isInWorkspace()) {
+ //this wizardpage is used in multiple wizards, not only in MavenProjectWizard
+ // the other wizard don't seem to have any getModel() methods.
+ //see MNGECLIPSE-1252 for more.
+ if (getWizard() instanceof MavenProjectWizard)
+ {
+ String projectName = getImportConfiguration().getProjectName(((MavenProjectWizard)getWizard()).getModel());
+ if(projectName.length()>0){
+ final IStatus locationStatus = workspace.validateProjectLocation(workspace.getRoot().getProject(projectName), projectPath);
+ if(!locationStatus.isOK()) {
+ setErrorMessage(locationStatus.getMessage());
+ setPageComplete(false);
+ return;
+ }
+ }
+ }
+ }
+
+ setPageComplete(true);
+ setErrorMessage(null);
+ setMessage(null);
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ProjectsImportPage.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ProjectsImportPage.java
new file mode 100644
index 00000000..5200f7bf
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ProjectsImportPage.java
@@ -0,0 +1,627 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRoot;
+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.OperationCanceledException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+import org.eclipse.ui.dialogs.IOverwriteQuery;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * The ProjectsImportPage is the page that allows the user to import projects from a particular location.
+ */
+public class ProjectsImportPage extends WizardPage implements IOverwriteQuery {
+
+ String location;
+
+ CheckboxTreeViewer projectsList;
+
+ IProject[] wsProjects;
+
+ ProjectRecord[] selectedProjects = new ProjectRecord[0];
+
+
+ public ProjectsImportPage(String location) {
+ super("wizardExternalProjectsPage"); //$NON-NLS-1$
+ this.location = location;
+
+ setTitle(Messages.ProjectsImportPage_title);
+ setDescription(Messages.ProjectsImportPage_desc);
+ setPageComplete(false);
+ }
+
+ public void createControl(Composite parent) {
+ initializeDialogUnits(parent);
+
+ Composite workArea = new Composite(parent, SWT.NONE);
+ setControl(workArea);
+
+ workArea.setLayout(new GridLayout());
+ workArea.setLayoutData(new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL));
+
+ createProjectsList(workArea);
+ createOptionsArea(workArea);
+ Dialog.applyDialogFont(workArea);
+
+ updateProjectsList(location);
+ }
+
+ /**
+ * Create the area with the extra options.
+ *
+ * @param workArea
+ */
+ private void createOptionsArea(Composite workArea) {
+ }
+
+ /**
+ * Create the checkbox list for the found projects.
+ *
+ * @param workArea
+ */
+ private void createProjectsList(Composite workArea) {
+ Label title = new Label(workArea, SWT.NONE);
+ title.setText(Messages.ProjectsImportPage_lstProjects);
+
+ Composite listComposite = new Composite(workArea, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 2;
+ layout.marginWidth = 0;
+ layout.makeColumnsEqualWidth = false;
+ listComposite.setLayout(layout);
+
+ listComposite.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.FILL_BOTH));
+
+ projectsList = new CheckboxTreeViewer(listComposite, SWT.BORDER);
+ GridData listData = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.FILL_BOTH);
+ projectsList.getControl().setLayoutData(listData);
+
+ projectsList.setContentProvider(new ITreeContentProvider() {
+
+ public Object[] getChildren(Object parentElement) {
+ return null;
+ }
+
+ public Object[] getElements(Object inputElement) {
+ return getValidProjects();
+ }
+
+ public boolean hasChildren(Object element) {
+ return false;
+ }
+
+ public Object getParent(Object element) {
+ return null;
+ }
+
+ public void dispose() {
+
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+ });
+
+ projectsList.setLabelProvider(new LabelProvider() {
+ public String getText(Object element) {
+ ProjectRecord projectRecord = (ProjectRecord) element;
+ return projectRecord.getProjectName() + " - " + projectRecord.projectFile.getParentFile().getAbsolutePath(); //$NON-NLS-1$
+ }
+ });
+
+ projectsList.addCheckStateListener(new ICheckStateListener() {
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ setPageComplete(projectsList.getCheckedElements().length > 0);
+ }
+ });
+
+ projectsList.setInput(this);
+ projectsList.setComparator(new ViewerComparator());
+ createSelectionButtons(listComposite);
+ }
+
+ /**
+ * Create the selection buttons in the listComposite.
+ *
+ * @param listComposite
+ */
+ private void createSelectionButtons(Composite listComposite) {
+ Composite buttonsComposite = new Composite(listComposite, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ buttonsComposite.setLayout(layout);
+
+ buttonsComposite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
+
+ Button selectAll = new Button(buttonsComposite, SWT.PUSH);
+ selectAll.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ selectAll.setText(Messages.ProjectsImportPage_btnSelect);
+ selectAll.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ projectsList.setCheckedElements(selectedProjects);
+ setPageComplete(projectsList.getCheckedElements().length > 0);
+ }
+ });
+ Dialog.applyDialogFont(selectAll);
+ setButtonLayoutData(selectAll);
+
+ Button deselectAll = new Button(buttonsComposite, SWT.PUSH);
+ deselectAll.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ deselectAll.setText(Messages.ProjectsImportPage_btnDeselect);
+ deselectAll.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ projectsList.setCheckedElements(new Object[0]);
+ setPageComplete(false);
+ }
+ });
+ Dialog.applyDialogFont(deselectAll);
+ setButtonLayoutData(deselectAll);
+
+ Button refresh = new Button(buttonsComposite, SWT.PUSH);
+ refresh.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ refresh.setText(Messages.ProjectsImportPage_btnRefresh);
+ refresh.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ updateProjectsList(location);
+ }
+ });
+ Dialog.applyDialogFont(refresh);
+ setButtonLayoutData(refresh);
+ }
+
+ /**
+ * Update the list of projects based on path. Method declared public only for test suite.
+ *
+ * @param path
+ */
+ void updateProjectsList(final String path) {
+ try {
+ getContainer().run(true, true, new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor) {
+ monitor.beginTask(Messages.ProjectsImportPage_task_search, 100);
+ File directory = new File(path);
+ selectedProjects = new ProjectRecord[0];
+ Collection<File> files = new ArrayList<File>();
+ monitor.worked(10);
+
+ if(directory.isDirectory()) {
+ if(!collectProjectFilesFromDirectory(files, directory, null, monitor)) {
+ return;
+ }
+ selectedProjects = new ProjectRecord[files.size()];
+ int index = 0;
+ monitor.worked(50);
+ monitor.subTask(Messages.ProjectsImportPage_task_processing);
+ for(File file : files) {
+ selectedProjects[index] = new ProjectRecord(file);
+ index++ ;
+ }
+ } else {
+ monitor.worked(60);
+ }
+ monitor.done();
+ }
+
+ });
+ } catch(InvocationTargetException e) {
+ MavenLogger.log(e.getMessage(), e);
+ } catch(InterruptedException e) {
+ // Nothing to do if the user interrupts.
+ }
+
+ projectsList.refresh(true);
+ projectsList.setCheckedElements(getValidProjects());
+ if(getValidProjects().length < selectedProjects.length) {
+ setMessage(Messages.ProjectsImportPage_message, WARNING);
+ } else {
+ setMessage(null, WARNING);
+ }
+ setPageComplete(projectsList.getCheckedElements().length > 0);
+ }
+
+ /**
+ * Collect the list of .project files that are under directory into files.
+ *
+ * @param files
+ * @param directory
+ * @param directoriesVisited Set of canonical paths of directories, used as recursion guard
+ * @param monitor The monitor to report to
+ * @return boolean <code>true</code> if the operation was completed.
+ */
+ boolean collectProjectFilesFromDirectory(Collection<File> files, File directory, Set<String> directoriesVisited,
+ IProgressMonitor monitor) {
+ if(monitor.isCanceled()) {
+ return false;
+ }
+
+ monitor.subTask(NLS.bind(Messages.ProjectsImportPage_task_checking, directory.getPath()));
+ File[] contents = directory.listFiles();
+ if(contents == null)
+ return false;
+
+ // Initialize recursion guard for recursive symbolic links
+ if(directoriesVisited == null) {
+ directoriesVisited = new HashSet<String>();
+ try {
+ directoriesVisited.add(directory.getCanonicalPath());
+ } catch(IOException exception) {
+ MavenLogger.log(exception.toString(), exception);
+ }
+ }
+
+ // first look for project description files
+ final String dotProject = IProjectDescription.DESCRIPTION_FILE_NAME;
+ for(File file : contents) {
+ if(file.isFile() && file.getName().equals(dotProject)) {
+ files.add(file);
+ // don't search sub-directories since we can't have nested
+ // projects
+ return true;
+ }
+ }
+
+ // no project description found, so recurse into sub-directories
+ for(File file : contents) {
+ if(file.isDirectory() && !IMavenConstants.METADATA_FOLDER.equals(file.getName())) {
+ try {
+ String canonicalPath = file.getCanonicalPath();
+ if(!directoriesVisited.add(canonicalPath)) {
+ // already been here --> do not recurse
+ continue;
+ }
+ } catch(IOException exception) {
+ MavenLogger.log(exception.toString(), exception);
+ }
+ collectProjectFilesFromDirectory(files, file, directoriesVisited, monitor);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Create the selected projects
+ *
+ * @return boolean <code>true</code> if all project creations were successful.
+ */
+ public boolean createProjects() {
+ final Object[] selected = projectsList.getCheckedElements();
+
+ WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
+ protected void execute(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ try {
+ monitor.beginTask("", selected.length); //$NON-NLS-1$
+ if(monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+
+ for(int i = 0; i < selected.length; i++ ) {
+ createExistingProject((ProjectRecord) selected[i], new SubProgressMonitor(monitor, 1));
+ }
+ } finally {
+ monitor.done();
+ }
+ }
+ };
+
+ // run the new project creation operation
+ try {
+ getContainer().run(true, true, op);
+ } catch(InterruptedException e) {
+ return false;
+ } catch(InvocationTargetException e) {
+ // one of the steps resulted in a core exception
+ Throwable t = e.getTargetException();
+ String message = Messages.ProjectsImportPage_error_creation;
+ IStatus status;
+ if(t instanceof CoreException) {
+ status = ((CoreException) t).getStatus();
+ } else {
+ status = new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, 1, message, t);
+ }
+ ErrorDialog.openError(getShell(), message, null, status);
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Performs clean-up if the user cancels the wizard without doing anything
+ */
+ public void performCancel() {
+ }
+
+ /**
+ * Create the project described in record. If it is successful return true.
+ *
+ * @param record
+ * @return boolean <code>true</code> if successful
+ * @throws InterruptedException
+ */
+ boolean createExistingProject(final ProjectRecord record, IProgressMonitor monitor)
+ throws InvocationTargetException, InterruptedException {
+ String projectName = record.getProjectName();
+ final IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ final IProject project = workspace.getRoot().getProject(projectName);
+ if(record.description == null) {
+ // error case
+ record.description = workspace.newProjectDescription(projectName);
+ IPath locationPath = new Path(record.projectFile.getAbsolutePath());
+
+ // If it is under the root use the default location
+ if(Platform.getLocation().isPrefixOf(locationPath)) {
+ record.description.setLocation(null);
+ } else {
+ record.description.setLocation(locationPath);
+ }
+ } else {
+ record.description.setName(projectName);
+ }
+
+ try {
+ monitor.beginTask(Messages.ProjectsImportPage_task_creating, 100);
+
+ @SuppressWarnings("deprecation")
+ IPath projectPath = record.description.getLocation();
+ if(projectPath!=null) {
+ MavenConsole console = MavenPlugin.getDefault().getConsole();
+
+ IWorkspaceRoot root = workspace.getRoot();
+
+ if(projectPath.toFile().equals(root.getLocation().toFile())) {
+ console.logError("Can't create project " + projectName + " at Workspace folder");
+ return false;
+ }
+
+ if(projectPath.removeLastSegments(1).toFile().equals(root.getLocation().toFile())) {
+ // rename dir in workspace to match expected project name
+ if(!projectPath.equals(root.getLocation().append(projectName))) {
+ File projectDir = projectPath.toFile();
+ File newProject = new File(projectDir.getParent(), projectName);
+ if(!projectDir.renameTo(newProject)) {
+ MavenLogger.log("Can't rename " + projectDir + " to " + newProject, null);
+ }
+ record.description.setLocation(null);
+ }
+ }
+ }
+
+ project.create(record.description, new SubProgressMonitor(monitor, 30));
+ project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 70));
+
+ } catch(CoreException e) {
+ throw new InvocationTargetException(e);
+ } finally {
+ monitor.done();
+ }
+
+ return true;
+ }
+
+ /**
+ * The <code>WizardDataTransfer</code> implementation of this <code>IOverwriteQuery</code> method asks the user
+ * whether the existing resource at the given path should be overwritten.
+ *
+ * @param pathString
+ * @return the user's reply: one of <code>"YES"</code>, <code>"NO"</code>, <code>"ALL"</code>, or
+ * <code>"CANCEL"</code>
+ */
+ public String queryOverwrite(String pathString) {
+ Path path = new Path(pathString);
+
+ String messageString;
+ // Break the message up if there is a file name and a directory
+ // and there are at least 2 segments.
+ if(path.getFileExtension() == null || path.segmentCount() < 2) {
+ messageString = NLS.bind(Messages.ProjectsImportPage_overwrite, pathString);
+ } else {
+ messageString = NLS.bind(Messages.ProjectsImportPage_overwrite2,
+ path.lastSegment(), path.removeLastSegments(1).toOSString());
+ }
+
+ final MessageDialog dialog = new MessageDialog(getContainer().getShell(), Messages.ProjectsImportPage_dialog_title, null,
+ messageString, MessageDialog.QUESTION, new String[] {IDialogConstants.YES_LABEL,
+ IDialogConstants.YES_TO_ALL_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.NO_TO_ALL_LABEL,
+ IDialogConstants.CANCEL_LABEL}, 0);
+ String[] response = new String[] {YES, ALL, NO, NO_ALL, CANCEL};
+ // run in syncExec because callback is from an operation,
+ // which is probably not running in the UI thread.
+ getControl().getDisplay().syncExec(new Runnable() {
+ public void run() {
+ dialog.open();
+ }
+ });
+ return dialog.getReturnCode() < 0 ? CANCEL : response[dialog.getReturnCode()];
+ }
+
+ /**
+ * Retrieve all the projects in the current workspace.
+ *
+ * @return IProject[] array of IProject in the current workspace
+ */
+ private IProject[] getProjectsInWorkspace() {
+ if(wsProjects == null) {
+ wsProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+ }
+ return wsProjects;
+ }
+
+ /**
+ * Method used for test suite.
+ *
+ * @return CheckboxTreeViewer the viewer containing all the projects found
+ */
+ public CheckboxTreeViewer getProjectsList() {
+ return projectsList;
+ }
+
+ /**
+ * Get the array of valid project records that can be imported from the source workspace or archive, selected by the
+ * user. If a project with the same name exists in both the source workspace and the current workspace, it will not
+ * appear in the list of projects to import and thus cannot be selected for import. Method declared public for test
+ * suite.
+ *
+ * @return ProjectRecord[] array of projects that can be imported into the workspace
+ */
+ public ProjectRecord[] getValidProjects() {
+ List<ProjectRecord> validProjects = new ArrayList<ProjectRecord>();
+ for(ProjectRecord projectRecord : selectedProjects) {
+ if(!isProjectInWorkspace(projectRecord.getProjectName())) {
+ validProjects.add(projectRecord);
+ }
+ }
+ return validProjects.toArray(new ProjectRecord[validProjects.size()]);
+ }
+
+ /**
+ * Determine if the project with the given name is in the current workspace.
+ *
+ * @param projectName String the project name to check
+ * @return boolean true if the project with the given name is in this workspace
+ */
+ private boolean isProjectInWorkspace(String projectName) {
+ if(projectName == null) {
+ return false;
+ }
+ IProject[] workspaceProjects = getProjectsInWorkspace();
+ for(int i = 0; i < workspaceProjects.length; i++ ) {
+ if(projectName.equals(workspaceProjects[i].getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+ /**
+ * Class declared public only for test suite.
+ */
+ public static class ProjectRecord {
+ File projectFile;
+
+ String projectName;
+
+ IProjectDescription description;
+
+ /**
+ * Create a record for a project based on the info in the file.
+ *
+ * @param file
+ */
+ ProjectRecord(File file) {
+ projectFile = file;
+ setProjectName();
+ }
+
+ /**
+ * Set the name of the project based on the projectFile.
+ */
+ private void setProjectName() {
+ IProjectDescription newDescription = null;
+ try {
+ IPath path = new Path(projectFile.getPath());
+ // if the file is in the default location, use the directory
+ // name as the project name
+ newDescription = ResourcesPlugin.getWorkspace().loadProjectDescription(path);
+
+ if(isDefaultLocation(path)) {
+ // projectName = path.segment(path.segmentCount() - 2);
+ // newDescription = ResourcesPlugin.getWorkspace().newProjectDescription(projectName);
+ }
+ } catch(CoreException e) {
+ // no good couldn't get the name
+ }
+
+ if(newDescription == null) {
+ this.description = null;
+ projectName = ""; //$NON-NLS-1$
+ } else {
+ this.description = newDescription;
+ projectName = this.description.getName();
+ }
+ }
+
+ /**
+ * Returns whether the given project description file path is in the default location for a project
+ *
+ * @param path The path to examine
+ * @return Whether the given path is the default location for a project
+ */
+ private boolean isDefaultLocation(IPath path) {
+ // The project description file must at least be within the project, which is within the workspace location
+ return path.segmentCount() > 1 && path.removeLastSegments(2).toFile().equals(Platform.getLocation().toFile());
+ }
+
+ /**
+ * Get the name of the project
+ *
+ * @return String
+ */
+ public String getProjectName() {
+ return projectName;
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ProjectsImportWizard.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ProjectsImportWizard.java
new file mode 100644
index 00000000..5e3c563d
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ProjectsImportWizard.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import org.eclipse.jface.wizard.Wizard;
+
+import org.eclipse.m2e.core.MavenImages;
+import org.eclipse.m2e.core.internal.Messages;
+
+/**
+ * WizardExtension
+ *
+ * @author Eugene Kuleshov
+ */
+public class ProjectsImportWizard extends Wizard {
+ private final String location;
+
+ private ProjectsImportPage mainPage;
+
+ public ProjectsImportWizard(String location) {
+ this.location = location;
+ setWindowTitle(Messages.ProjectsImportWizard_title);
+ setDefaultPageImageDescriptor(MavenImages.WIZ_IMPORT_WIZ);
+ }
+
+ public void addPages() {
+ mainPage = new ProjectsImportPage(this.location);
+ addPage(mainPage);
+ }
+
+ public boolean performCancel() {
+ mainPage.performCancel();
+ return true;
+ }
+
+ public boolean performFinish() {
+ return mainPage.createProjects();
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ResolverConfigurationComponent.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ResolverConfigurationComponent.java
new file mode 100644
index 00000000..f94e4bff
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/ResolverConfigurationComponent.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.events.ExpansionAdapter;
+import org.eclipse.ui.forms.events.ExpansionEvent;
+import org.eclipse.ui.forms.widgets.ExpandableComposite;
+
+import org.eclipse.m2e.core.core.Messages;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+import org.eclipse.m2e.core.project.ResolverConfiguration;
+
+
+/**
+ * A foldable resolver configuration panel
+ */
+public class ResolverConfigurationComponent extends ExpandableComposite {
+
+ private static final String[] DEFAULT_NAME_TEMPLATES = {"[artifactId]", // //$NON-NLS-1$
+ "[artifactId]-TRUNK", // //$NON-NLS-1$
+ "[artifactId]-[version]", // //$NON-NLS-1$
+ "[groupId].[artifactId]", "[groupId].[artifactId]-[version]"}; //$NON-NLS-1$ //$NON-NLS-2$
+
+ /** The resolver configuration */
+ protected final ResolverConfiguration resolverConfiguration;
+
+ /** project import configuration */
+ private final ProjectImportConfiguration projectImportConfiguration;
+
+ private ModifyListener modifyListener;
+
+ Button resolveWorkspaceProjects;
+
+ Text profiles;
+
+ Combo template;
+
+ /** Creates a new component. */
+ public ResolverConfigurationComponent(final Composite parent,
+ final ProjectImportConfiguration propectImportConfiguration, final boolean enableProjectNameTemplate) {
+ super(parent, ExpandableComposite.COMPACT | ExpandableComposite.TWISTIE | ExpandableComposite.EXPANDED);
+ this.projectImportConfiguration = propectImportConfiguration;
+ this.resolverConfiguration = propectImportConfiguration.getResolverConfiguration();
+
+ setText(Messages.getString("resolverConfiguration.advanced")); //$NON-NLS-1$
+
+ final Composite advancedComposite = new Composite(this, SWT.NONE);
+ setClient(advancedComposite);
+ addExpansionListener(new ExpansionAdapter() {
+ public void expansionStateChanged(ExpansionEvent e) {
+ Shell shell = parent.getShell();
+ Point minSize = shell.getMinimumSize();
+ shell.setMinimumSize(shell.getSize().x, minSize.y);
+ shell.pack();
+ parent.layout();
+ shell.setMinimumSize(minSize);
+ }
+ });
+
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.marginLeft = 11;
+ gridLayout.numColumns = 2;
+ advancedComposite.setLayout(gridLayout);
+
+ resolveWorkspaceProjects = new Button(advancedComposite, SWT.CHECK);
+ resolveWorkspaceProjects.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+ resolveWorkspaceProjects.setText(Messages.getString("resolverConfiguration.resolveWorkspaceProjects")); //$NON-NLS-1$
+ resolveWorkspaceProjects.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ resolverConfiguration.setResolveWorkspaceProjects(resolveWorkspaceProjects.getSelection());
+ }
+ });
+
+ Label profilesLabel = new Label(advancedComposite, SWT.NONE);
+ profilesLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+ profilesLabel.setText(Messages.getString("resolverConfiguration.profiles")); //$NON-NLS-1$
+
+ profiles = new Text(advancedComposite, SWT.BORDER);
+ profiles.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ profiles.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ resolverConfiguration.setActiveProfiles(profiles.getText());
+ }
+ });
+
+ if(enableProjectNameTemplate) {
+ Label templateLabel = new Label(advancedComposite, SWT.NONE);
+ templateLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+ templateLabel.setText(Messages.getString("resolverConfiguration.template")); //$NON-NLS-1$
+
+ template = new Combo(advancedComposite, SWT.BORDER);
+ template.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ template.setToolTipText(Messages.getString("resolverConfiguration.templateDescription")); //$NON-NLS-1$
+ template.setItems(DEFAULT_NAME_TEMPLATES);
+ template.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ propectImportConfiguration.setProjectNameTemplate(template.getText());
+ }
+ });
+ }
+
+ loadData();
+ }
+
+ public void loadData() {
+ resolveWorkspaceProjects.setSelection(resolverConfiguration.shouldResolveWorkspaceProjects());
+ profiles.setText(resolverConfiguration.getActiveProfiles());
+ if(template != null) {
+ template.setText(projectImportConfiguration.getProjectNameTemplate());
+ }
+ }
+
+ public ResolverConfiguration getResolverConfiguration() {
+ return this.resolverConfiguration;
+ }
+
+ public void setModifyListener(ModifyListener modifyListener) {
+ this.modifyListener = modifyListener;
+
+ if(template != null) {
+ template.addModifyListener(modifyListener);
+ }
+ }
+
+ public void dispose() {
+ super.dispose();
+
+ if(modifyListener != null) {
+ template.removeModifyListener(modifyListener);
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/WidthGroup.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/WidthGroup.java
new file mode 100644
index 00000000..c6f8c77e
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/WidthGroup.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.HashSet;
+
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Group of controls with the same width
+ *
+ * @author Eugene Kuleshov
+ */
+public class WidthGroup extends ControlAdapter {
+
+ private final HashSet<Control> controls = new HashSet<Control>();
+
+ public void controlResized(ControlEvent e) {
+ int maxWidth = 0;
+ for(Control c : this.controls) {
+ int width = c.getSize().x;
+ if(width > maxWidth) {
+ maxWidth = width;
+ }
+ }
+ if(maxWidth > 0) {
+ for(Control c : this.controls) {
+ GridData gd = (GridData) c.getLayoutData();
+ gd.widthHint = maxWidth;
+ c.getParent().layout();
+ }
+ }
+ }
+
+ public void addControl(Control control) {
+ controls.add(control);
+ control.getParent().layout();
+ }
+
+}
+
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/WorkingSetGroup.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/WorkingSetGroup.java
new file mode 100644
index 00000000..0d7bf352
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/wizards/WorkingSetGroup.java
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.wizards;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.resource.DeviceResourceException;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.IWorkingSetSelectionDialog;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.project.ProjectImportConfiguration;
+
+
+/**
+ * Working set group
+ *
+ * @author Eugene Kuleshov
+ */
+public class WorkingSetGroup {
+
+ static final List<String> WORKING_SET_IDS = Arrays.asList( //
+ "org.eclipse.ui.resourceWorkingSetPage", "org.eclipse.jdt.ui.JavaWorkingSetPage"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ ComboViewer workingsetComboViewer;
+
+ Button addToWorkingSetButton;
+
+ final ProjectImportConfiguration configuration;
+
+ final Shell shell;
+
+ public WorkingSetGroup(Composite container, ProjectImportConfiguration configuration, Shell shell) {
+ this.configuration = configuration;
+ this.shell = shell;
+
+ createControl(container);
+ }
+
+ private void createControl(Composite container) {
+ addToWorkingSetButton = new Button(container, SWT.CHECK);
+ GridData gd_addToWorkingSetButton = new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1);
+ gd_addToWorkingSetButton.verticalIndent = 12;
+ addToWorkingSetButton.setLayoutData(gd_addToWorkingSetButton);
+ addToWorkingSetButton.setSelection(true);
+ addToWorkingSetButton.setData("name", "addToWorkingSetButton"); //$NON-NLS-1$ //$NON-NLS-2$
+ addToWorkingSetButton.setText(Messages.WorkingSetGroup_btnAddSet);
+ addToWorkingSetButton.setSelection(false);
+
+ final Label workingsetLabel = new Label(container, SWT.NONE);
+ GridData gd_workingsetLabel = new GridData();
+ gd_workingsetLabel.horizontalIndent = 10;
+ workingsetLabel.setLayoutData(gd_workingsetLabel);
+ workingsetLabel.setEnabled(false);
+ workingsetLabel.setData("name", "workingsetLabel"); //$NON-NLS-1$ //$NON-NLS-2$
+ workingsetLabel.setText(Messages.WorkingSetGroup_lblSet);
+
+ Combo workingsetCombo = new Combo(container, SWT.READ_ONLY);
+ workingsetCombo.setEnabled(false);
+ workingsetCombo.setData("name", "workingsetCombo"); //$NON-NLS-1$ //$NON-NLS-2$
+ workingsetCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ workingsetComboViewer = new ComboViewer(workingsetCombo);
+ workingsetComboViewer.setContentProvider(new IStructuredContentProvider() {
+ public Object[] getElements(Object input) {
+ if(input instanceof IWorkingSet[]) {
+ return (IWorkingSet[]) input;
+ } else if(input instanceof List<?>) {
+ return new Object[] {input};
+ } else if(input instanceof Set<?>) {
+ return ((Set<?>) input).toArray();
+ }
+ return new IWorkingSet[0];
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ public void dispose() {
+ }
+ });
+ workingsetComboViewer.setLabelProvider(new LabelProvider() {
+ private ResourceManager images = new LocalResourceManager(JFaceResources.getResources());
+
+ @SuppressWarnings("deprecation")
+ public Image getImage(Object element) {
+ if(element instanceof IWorkingSet) {
+ ImageDescriptor imageDescriptor = ((IWorkingSet) element).getImage();
+ if(imageDescriptor != null) {
+ try {
+ return (Image) images.create(imageDescriptor);
+ } catch(DeviceResourceException ex) {
+ return null;
+ }
+ }
+ }
+ return super.getImage(element);
+ }
+
+ public String getText(Object element) {
+ if(element instanceof IWorkingSet) {
+ return ((IWorkingSet) element).getLabel();
+ } else if(element instanceof List<?>) {
+ StringBuffer sb = new StringBuffer();
+ for(Object o : (List<?>) element) {
+ if(o instanceof IWorkingSet) {
+ if(sb.length() > 0) {
+ sb.append(", "); //$NON-NLS-1$
+ }
+ sb.append(((IWorkingSet) o).getLabel());
+ }
+ }
+ return sb.toString();
+ }
+ return super.getText(element);
+ }
+
+ public void dispose() {
+ images.dispose();
+ super.dispose();
+ }
+ });
+
+ workingsetComboViewer.setComparator(new ViewerComparator());
+
+ final Button newWorkingSetButton = new Button(container, SWT.NONE);
+ newWorkingSetButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ newWorkingSetButton.setData("name", "configureButton"); //$NON-NLS-1$ //$NON-NLS-2$
+ newWorkingSetButton.setText(Messages.WorkingSetGroup_btnMore);
+ newWorkingSetButton.setEnabled(false);
+ newWorkingSetButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(final SelectionEvent e) {
+ IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
+ IWorkingSetSelectionDialog dialog = workingSetManager.createWorkingSetSelectionDialog(shell, true,
+ WORKING_SET_IDS.toArray(new String[0]));
+ if(dialog.open() == Window.OK) {
+ IWorkingSet[] workingSets = dialog.getSelection();
+
+ selectWorkingSets(workingSets);
+ }
+ }
+ });
+
+ if(selectWorkingSets(configuration.getWorkingSets())) {
+ addToWorkingSetButton.setSelection(true);
+ workingsetLabel.setEnabled(true);
+ workingsetComboViewer.getCombo().setEnabled(true);
+ newWorkingSetButton.setEnabled(true);
+ }
+
+ addToWorkingSetButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ boolean addToWorkingingSet = addToWorkingSetButton.getSelection();
+ workingsetLabel.setEnabled(addToWorkingingSet);
+ workingsetComboViewer.getCombo().setEnabled(addToWorkingingSet);
+ newWorkingSetButton.setEnabled(addToWorkingingSet);
+ if(addToWorkingingSet) {
+ updateConfiguration();
+ } else {
+ configuration.setWorkingSet(null);
+ }
+ }
+ });
+
+ workingsetComboViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ updateConfiguration();
+ }
+ });
+ }
+
+ protected void updateConfiguration() {
+ if(addToWorkingSetButton.getSelection()) {
+ IStructuredSelection selection = (IStructuredSelection) workingsetComboViewer.getSelection();
+ Object o = selection.getFirstElement();
+ if(o != null) {
+ if(o instanceof IWorkingSet) {
+ configuration.setWorkingSet((IWorkingSet) o);
+ } else if(o instanceof List<?>) {
+ List<?> l = (List<?>) o;
+ configuration.setWorkingSets(l.toArray(new IWorkingSet[l.size()]));
+ }
+ }
+ }
+ }
+
+ Set<IWorkingSet> getWorkingSets() {
+ Set<IWorkingSet> workingSets = new HashSet<IWorkingSet>();
+
+ IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
+ for(IWorkingSet workingSet : workingSetManager.getWorkingSets()) {
+ if(!workingSet.isEmpty()) {
+ IAdaptable[] elements = workingSet.getElements();
+ IResource resource = (IResource) elements[0].getAdapter(IResource.class);
+ if(resource != null) {
+ workingSets.add(workingSet);
+ }
+ } else {
+ if(WORKING_SET_IDS.contains(workingSet.getId())) {
+ workingSets.add(workingSet);
+ }
+ }
+ }
+
+ return workingSets;
+ }
+
+ public void dispose() {
+ workingsetComboViewer.getLabelProvider().dispose();
+ }
+
+ protected boolean selectWorkingSets(IWorkingSet[] workingSets) {
+ Set<IWorkingSet> defaultSets = getWorkingSets();
+ workingsetComboViewer.setInput(defaultSets);
+
+ if(workingSets != null && workingSets.length > 0) {
+ if(workingSets.length == 1) {
+ IWorkingSet workingSet = workingSets[0];
+ if(defaultSets.contains(workingSet)) {
+ workingsetComboViewer.setSelection(new StructuredSelection(workingSet));
+ }
+ } else {
+ List<?> list = Arrays.asList(workingSets);
+ workingsetComboViewer.add(list);
+ workingsetComboViewer.setSelection(new StructuredSelection((Object) list));
+ }
+ return true;
+ }
+ return false;
+ }
+}

Back to the top