Browse files

Merge remote-tracking branch 'origin/master' into NXCM-4867-indexer-s…

…ync-simple

Conflicts:
	plugins/indexer/nexus-indexer-lucene-plugin/pom.xml
	plugins/indexer/nexus-indexer-lucene-plugin/src/main/java/org/sonatype/nexus/index/DefaultIndexerManager.java
  • Loading branch information...
2 parents 2fc19c9 + 1a148aa commit d8770311d96e77817cabc97f11a893e088b3fb64 @scarlucci scarlucci committed Apr 30, 2013
Showing with 5,560 additions and 124,827 deletions.
  1. +5 −0 nexus-bootstrap/pom.xml
  2. +111 −0 ...ootstrap/src/main/java/org/sonatype/nexus/bootstrap/jetty/InstrumentedSelectChannelConnector.java
  3. +48 −0 nexus-client-core-testsuite/src/test/java/org/sonatype/nexus/client/testsuite/UserIT.java
  4. +85 −0 nexus-client-core/src/main/java/org/sonatype/nexus/client/internal/util/Version.java
  5. +9 −2 nexus-client-core/src/main/java/org/sonatype/nexus/client/rest/jersey/JerseyNexusClientFactory.java
  6. +2 −0 ...test/filtered-resources/META-INF/maven/org.sonatype.nexus.client/nexus-client-core/pom.properties
  7. +64 −0 ...-core/src/test/java/org/sonatype/nexus/client/rest/jersey/JerseyNexusTestClientUserAgentTest.java
  8. +22 −2 nexus-core/pom.xml
  9. +9 −1 nexus-core/src/main/java/org/sonatype/nexus/AbstractApplicationStatusSource.java
  10. +1 −2 nexus-core/src/main/java/org/sonatype/nexus/apachehttpclient/Hc4ProviderBase.java
  11. +2 −1 nexus-core/src/main/java/org/sonatype/nexus/apachehttpclient/Hc4ProviderImpl.java
  12. +86 −0 nexus-core/src/main/java/org/sonatype/nexus/apachehttpclient/InstrumentedHttpClient.java
  13. +128 −0 nexus-core/src/main/java/org/sonatype/nexus/apachehttpclient/InstrumentedRequestDirector.java
  14. +44 −0 nexus-core/src/main/java/org/sonatype/nexus/email/DefaultNexusEmailer.java
  15. +60 −0 nexus-core/src/main/java/org/sonatype/nexus/formfields/RepoTargetComboFormField.java
  16. +57 −0 nexus-core/src/main/java/org/sonatype/nexus/guice/AbstractInterceptorModule.java
  17. +37 −0 nexus-core/src/main/java/org/sonatype/nexus/guice/FilterChainModule.java
  18. +2 −2 nexus-core/src/main/java/org/sonatype/nexus/guice/NexusModules.java
  19. +84 −0 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/AbstractFileDeletingWalkerProcessor.java
  20. +413 −0 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/DefaultReleaseRemover.java
  21. +29 −56 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/DefaultSnapshotRemover.java
  22. +57 −0 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/ReleaseRemovalRequest.java
  23. +69 −0 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/ReleaseRemovalResult.java
  24. +28 −0 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/ReleaseRemover.java
  25. +59 −0 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/ReleaseRemoverTask.java
  26. +11 −2 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/SnapshotRemovalRequest.java
  27. +15 −1 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/SnapshotRemoverTask.java
  28. +72 −0 ...s-core/src/main/java/org/sonatype/nexus/maven/tasks/descriptors/ReleaseRemovalTaskDescriptor.java
  29. +13 −2 ...-core/src/main/java/org/sonatype/nexus/maven/tasks/descriptors/SnapshotRemovalTaskDescriptor.java
  30. +61 −10 nexus-core/src/main/java/org/sonatype/nexus/mime/DefaultMimeSupport.java
  31. +1 −3 nexus-core/src/main/java/org/sonatype/nexus/mime/NexusExtensionMimeDetector.java
  32. +13 −6 nexus-core/src/main/java/org/sonatype/nexus/plugins/DefaultNexusPluginManager.java
  33. +3 −0 nexus-core/src/main/java/org/sonatype/nexus/plugins/rest/AbstractNexusIndexHtmlCustomizer.java
  34. +0 −146 nexus-core/src/main/java/org/sonatype/nexus/plugins/rest/AbstractUiContributionBuilder.java
  35. +0 −79 nexus-core/src/main/java/org/sonatype/nexus/plugins/rest/IndexHtmlSnippetBuilder.java
  36. +1 −2 nexus-core/src/main/java/org/sonatype/nexus/plugins/rest/NexusIndexHtmlCustomizer.java
  37. +0 −153 nexus-core/src/main/java/org/sonatype/nexus/plugins/rest/UiContributionBuilder.java
  38. +0 −89 nexus-core/src/main/java/org/sonatype/nexus/plugins/rest/UiContributor.java
  39. +206 −22 nexus-core/src/main/java/org/sonatype/nexus/proxy/ItemNotFoundException.java
  40. +29 −11 nexus-core/src/main/java/org/sonatype/nexus/proxy/ResourceStoreRequest.java
  41. +1 −1 nexus-core/src/main/java/org/sonatype/nexus/proxy/item/AbstractStorageItem.java
  42. +20 −1 nexus-core/src/main/java/org/sonatype/nexus/proxy/item/AbstractWrappingContentLocator.java
  43. +16 −1 nexus-core/src/main/java/org/sonatype/nexus/proxy/item/PreparedContentLocator.java
  44. +6 −3 nexus-core/src/main/java/org/sonatype/nexus/proxy/mapping/DefaultRequestRepositoryMapper.java
  45. +8 −0 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/AbstractChecksumContentValidator.java
  46. +36 −1 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/AbstractMavenRepository.java
  47. +11 −4 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/ArtifactStoreHelper.java
  48. +1 −1 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/ChecksumContentValidator.java
  49. +18 −0 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/ChecksumPolicy.java
  50. +89 −56 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/LayoutConverterShadowRepository.java
  51. +5 −3 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/maven1/M1LayoutedM2ShadowRepository.java
  52. +13 −10 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/maven2/M2GroupRepository.java
  53. +6 −3 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/maven2/M2LayoutedM1ShadowRepository.java
  54. +4 −3 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/metadata/operations/AddPluginOperation.java
  55. +7 −6 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/metadata/operations/MetadataUtil.java
  56. +20 −0 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/routing/internal/FilePrefixSource.java
  57. +43 −9 nexus-core/src/main/java/org/sonatype/nexus/proxy/maven/routing/internal/ManagerImpl.java
  58. +10 −1 ...re/src/main/java/org/sonatype/nexus/proxy/maven/routing/internal/RemoteContentDiscovererImpl.java
  59. +6 −3 ...-core/src/main/java/org/sonatype/nexus/proxy/maven/routing/internal/RemotePrefixFileStrategy.java
  60. +71 −62 ...re/src/main/java/org/sonatype/nexus/proxy/maven/routing/internal/scrape/AmazonS3IndexScraper.java
  61. +2 −1 nexus-core/src/main/java/org/sonatype/nexus/proxy/registry/RepositoryRegistry.java
  62. +36 −9 nexus-core/src/main/java/org/sonatype/nexus/proxy/repository/AbstractGroupRepository.java
  63. +59 −47 nexus-core/src/main/java/org/sonatype/nexus/proxy/repository/AbstractProxyRepository.java
  64. +92 −94 nexus-core/src/main/java/org/sonatype/nexus/proxy/repository/AbstractRepository.java
  65. +0 −55 nexus-core/src/main/java/org/sonatype/nexus/proxy/repository/AbstractRequestProcessor.java
  66. +50 −0 nexus-core/src/main/java/org/sonatype/nexus/proxy/repository/AbstractRequestStrategy.java
  67. +49 −14 nexus-core/src/main/java/org/sonatype/nexus/proxy/repository/AbstractShadowRepository.java
  68. +31 −4 nexus-core/src/main/java/org/sonatype/nexus/proxy/repository/GroupItemNotFoundException.java
  69. +28 −3 nexus-core/src/main/java/org/sonatype/nexus/proxy/repository/Repository.java
  70. +0 −76 nexus-core/src/main/java/org/sonatype/nexus/proxy/repository/RequestProcessor.java
  71. +99 −0 nexus-core/src/main/java/org/sonatype/nexus/proxy/repository/RequestStrategy.java
  72. +0 −66 nexus-core/src/main/java/org/sonatype/nexus/proxy/repository/ShadowRepositoryEventInspector.java
  73. +20 −9 nexus-core/src/main/java/org/sonatype/nexus/proxy/router/DefaultRepositoryRouter.java
  74. +10 −0 nexus-core/src/main/java/org/sonatype/nexus/proxy/router/RequestRoute.java
  75. +74 −36 ...core/src/main/java/org/sonatype/nexus/proxy/storage/local/fs/DefaultFSLocalRepositoryStorage.java
  76. +48 −34 nexus-core/src/main/java/org/sonatype/nexus/proxy/storage/local/fs/DefaultFSPeer.java
  77. +17 −7 nexus-core/src/main/java/org/sonatype/nexus/proxy/storage/remote/RemoteItemNotFoundException.java
  78. +2 −6 ...ava/org/sonatype/nexus/proxy/storage/remote/commonshttpclient/CommonsHttpClientRemoteStorage.java
  79. +3 −9 ...ore/src/main/java/org/sonatype/nexus/proxy/storage/remote/httpclient/HttpClientRemoteStorage.java
  80. +5 −1 nexus-core/src/main/java/org/sonatype/nexus/scheduling/AbstractNexusRepositoriesTask.java
  81. +45 −0 nexus-core/src/main/java/org/sonatype/nexus/security/FilterChain.java
  82. +0 −39 nexus-core/src/main/java/org/sonatype/nexus/timing/Timed.java
  83. +0 −104 nexus-core/src/main/java/org/sonatype/nexus/timing/TimedInterceptor.java
  84. +0 −32 nexus-core/src/main/java/org/sonatype/nexus/timing/TimingModule.java
  85. +23 −0 nexus-core/src/main/java/org/sonatype/nexus/util/Condition.java
  86. +48 −0 nexus-core/src/main/java/org/sonatype/nexus/velocity/NexusVelocityConfigurator.java
  87. +68 −50 nexus-core/src/main/java/org/sonatype/scheduling/DefaultTaskConfigManager.java
  88. +26 −0 nexus-core/src/main/resources/META-INF/nexus/static-security.xml
  89. +55 −54 nexus-core/src/main/resources/META-INF/security/security.xml
  90. +5 −0 nexus-core/src/test/java/org/sonatype/nexus/AbstractMavenRepoContentTests.java
  91. +156 −0 nexus-core/src/test/java/org/sonatype/nexus/maven/tasks/DefaultReleaseRemoverIT.java
  92. +219 −0 nexus-core/src/test/java/org/sonatype/nexus/maven/tasks/DefaultReleaseRemoverTest.java
  93. +111 −1 nexus-core/src/test/java/org/sonatype/nexus/maven/tasks/DefaultSnapshotRemoverIT.java
  94. +4 −1 nexus-core/src/test/java/org/sonatype/nexus/plugins/DefaultNexusPluginManagerTest.java
  95. +15 −16 nexus-core/src/test/java/org/sonatype/nexus/proxy/SimplePullTest.java
  96. +116 −0 nexus-core/src/test/java/org/sonatype/nexus/proxy/maven/M2RepositoryDeleteArtifactTest.java
  97. +104 −0 ...core/src/test/java/org/sonatype/nexus/proxy/maven/metadata/operations/AddPluginOperationTest.java
  98. +189 −0 ...t/java/org/sonatype/nexus/proxy/maven/routing/internal/PrefixFileForProxiesAreUnmodifiedTest.java
  99. +44 −0 ...e/src/test/java/org/sonatype/nexus/proxy/maven/routing/internal/RemotePrefixFileStrategyTest.java
  100. +1 −1 ...test/java/org/sonatype/nexus/proxy/maven/routing/internal/TextFilePrefixSourceMarshallerTest.java
  101. +267 −72 ...rc/test/java/org/sonatype/nexus/proxy/maven/routing/internal/scrape/AmazonS3IndexScraperTest.java
  102. +115 −0 ...est/java/org/sonatype/nexus/proxy/maven/routing/internal/scrape/AmazonS3LiveIndexScraperTest.java
  103. +67 −0 ...src/test/java/org/sonatype/nexus/proxy/maven/routing/internal/scrape/S3PagedDeliverBehaviour.java
  104. +39 −0 .../test/java/org/sonatype/nexus/proxy/maven/routing/internal/scrape/S3ResponseHeadersBehaviour.java
  105. +111 −0 ...c/test/java/org/sonatype/nexus/proxy/storage/local/fs/NEXUS5468ConnectionLeakOnStoreItemTest.java
  106. +216 −0 .../java/org/sonatype/nexus/proxy/storage/local/fs/NEXUS5612DefaultFSLocalRepositoryStorageTest.java
  107. +3 −3 ...org/sonatype/nexus/proxy/storage/remote/commonshttpclient/CommonsHttpClientRemoteStorageTest.java
  108. +3 −3 ...src/test/java/org/sonatype/nexus/proxy/storage/remote/httpclient/HttpClientRemoteStorageTest.java
  109. +41 −0 nexus-core/src/test/java/org/sonatype/nexus/velocity/NexusVelocityConfiguratorTest.java
  110. +3 −2 nexus-core/src/test/java/org/sonatype/scheduling/DefaultTaskConfigManagerTest.java
  111. BIN nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0.1/test-1.0.1-sources.jar
  112. +1 −0 nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0.1/test-1.0.1-sources.jar.sha1
  113. BIN nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0.1/test-1.0.1.jar
  114. +1 −0 nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0.1/test-1.0.1.jar.sha1
  115. +29 −0 nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0.1/test-1.0.1.pom
  116. +1 −0 nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0.1/test-1.0.1.pom.sha1
  117. BIN nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0/test-1.0-sources.jar
  118. +1 −0 nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0/test-1.0-sources.jar.sha1
  119. BIN nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0/test-1.0.jar
  120. +1 −0 nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0/test-1.0.jar.sha1
  121. +29 −0 nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0/test-1.0.pom
  122. +1 −0 nexus-core/src/test/resources/reposes/releases/org/sonatype/test/1.0/test-1.0.pom.sha1
  123. BIN ...re/src/test/resources/reposes/releases/org/sonatype/test/2.1000.9999/test-2.1000.9999-sources.jar
  124. +1 −0 ...c/test/resources/reposes/releases/org/sonatype/test/2.1000.9999/test-2.1000.9999-sources.jar.sha1
  125. BIN nexus-core/src/test/resources/reposes/releases/org/sonatype/test/2.1000.9999/test-2.1000.9999.jar
  126. +1 −0 ...-core/src/test/resources/reposes/releases/org/sonatype/test/2.1000.9999/test-2.1000.9999.jar.sha1
  127. +29 −0 nexus-core/src/test/resources/reposes/releases/org/sonatype/test/2.1000.9999/test-2.1000.9999.pom
  128. +1 −0 ...-core/src/test/resources/reposes/releases/org/sonatype/test/2.1000.9999/test-2.1000.9999.pom.sha1
  129. +1 −1 ...her/src/main/java/org/sonatype/nexus/bundle/launcher/support/DefaultNexusBundleConfiguration.java
  130. +4 −0 nexus-logging-extras/src/main/resources/META-INF/log/logback-nexus.xml
  131. +1 −1 nexus-logging-extras/src/main/resources/META-INF/log/logback.properties
  132. +15 −0 nexus-oss-webapp/pom.xml
  133. +4 −0 nexus-oss-webapp/src/main/assembly/bundle.xml
  134. +9 −7 nexus-oss-webapp/src/main/resources/content/bin/jsw/conf/wrapper.conf
  135. +2 −2 nexus-oss-webapp/src/main/resources/content/conf/jetty.xml
  136. +21 −0 nexus-plugin-api/pom.xml
  137. +1 −1 nexus-runtime-platform/pom.xml
  138. +2 −2 ...test/java/org/sonatype/nexus/integrationtests/nexus4579/Nexus4579OptionalTrashForSnapshotsIT.java
  139. +3 −1 ...c/test/java/org/sonatype/nexus/integrationtests/upgrades/nexus652/Nexus652Beta5To10UpgradeIT.java
  140. +2 −0 ...ness-launcher/src/main/java/org/sonatype/nexus/integrationtests/AbstractNexusIntegrationTest.java
  141. +6 −2 ...t/nexus-test-harness-launcher/src/main/java/org/sonatype/nexus/test/booter/Jetty8NexusBooter.java
  142. +75 −0 nexus-web-utils/src/main/java/org/sonatype/nexus/web/FilterChainInstaller.java
  143. +93 −0 nexus-web-utils/src/main/java/org/sonatype/nexus/web/MdcUserContextFilter.java
  144. +25 −100 nexus-webapp/pom.xml
  145. +122 −0 nexus-webapp/src/main/java/org/sonatype/nexus/webapp/MetricsModule.java
  146. +32 −0 nexus-webapp/src/main/java/org/sonatype/nexus/webapp/WebappModule.java
  147. +0 −3,324 nexus-webapp/src/main/webapp/ext-3.4.1/adapter/ext/ext-base-debug.js
  148. +0 −18 nexus-webapp/src/main/webapp/ext-3.4.1/adapter/ext/ext-base.js
  149. +0 −2,232 nexus-webapp/src/main/webapp/ext-3.4.1/adapter/jquery/ext-jquery-adapter-debug.js
  150. +0 −18 nexus-webapp/src/main/webapp/ext-3.4.1/adapter/jquery/ext-jquery-adapter.js
  151. +0 −2,261 nexus-webapp/src/main/webapp/ext-3.4.1/adapter/prototype/ext-prototype-adapter-debug.js
  152. +0 −18 nexus-webapp/src/main/webapp/ext-3.4.1/adapter/prototype/ext-prototype-adapter.js
  153. +0 −2,027 nexus-webapp/src/main/webapp/ext-3.4.1/adapter/yui/ext-yui-adapter-debug.js
  154. +0 −18 nexus-webapp/src/main/webapp/ext-3.4.1/adapter/yui/ext-yui-adapter.js
  155. +0 −52,237 nexus-webapp/src/main/webapp/ext-3.4.1/ext-all-debug-w-comments.js
  156. +0 −52,237 nexus-webapp/src/main/webapp/ext-3.4.1/ext-all-debug.js
  157. +0 −18 nexus-webapp/src/main/webapp/ext-3.4.1/ext-all.js
  158. +0 −24 nexus-webapp/src/main/webapp/ext-3.4.1/license.txt
  159. +0 −125 nexus-webapp/src/main/webapp/ext-3.4.1/release-notes.html
  160. +0 −54 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/debug.css
  161. +0 −5,347 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/ext-all-notheme.css
  162. +0 −18 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/ext-all.css
  163. +0 −18 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/reset-min.css
  164. +0 −65 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/borders.css
  165. +0 −91 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/box.css
  166. +0 −456 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/button.css
  167. +0 −56 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/combo.css
  168. +0 −356 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/core.css
  169. +0 −282 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/date-picker.css
  170. +0 −72 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/dd.css
  171. +0 −37 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/debug.css
  172. +0 −70 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/dialog.css
  173. +0 −103 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/editor.css
  174. +0 −608 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/form.css
  175. +0 −604 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/grid.css
  176. +0 −307 nexus-webapp/src/main/webapp/ext-3.4.1/resources/css/structure/layout.css
Sorry, we could not display the entire diff because too many files (1,944) changed.
View
5 nexus-bootstrap/pom.xml
@@ -41,6 +41,11 @@
</dependency>
<dependency>
+ <groupId>com.yammer.metrics</groupId>
+ <artifactId>metrics-jetty</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>tanukisoft</groupId>
<artifactId>wrapper</artifactId>
<scope>provided</scope>
View
111 .../src/main/java/org/sonatype/nexus/bootstrap/jetty/InstrumentedSelectChannelConnector.java
@@ -0,0 +1,111 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.bootstrap.jetty;
+
+import com.yammer.metrics.Metrics;
+import com.yammer.metrics.core.Counter;
+import com.yammer.metrics.core.Meter;
+import com.yammer.metrics.core.MetricsRegistry;
+import com.yammer.metrics.core.Timer;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.server.nio.SelectChannelConnector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Custom re-implementation of {@link com.yammer.metrics.jetty.InstrumentedSelectChannelConnector}
+ * which sets up metrics collection on {@link #doStart()} instead of in CTOR.
+ *
+ * @since 2.5
+ */
+public final class InstrumentedSelectChannelConnector
+ extends SelectChannelConnector
+{
+ private static final Logger log = LoggerFactory.getLogger(InstrumentedSelectChannelConnector.class);
+
+ private final MetricsRegistry registry;
+
+ private Timer duration;
+
+ private Meter accepts, connects, disconnects;
+
+ private Counter connections;
+
+ public InstrumentedSelectChannelConnector() {
+ registry = Metrics.defaultRegistry();
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ String port = String.valueOf(getPort());
+
+ this.duration = registry.newTimer(SelectChannelConnector.class,
+ "connection-duration",
+ port,
+ TimeUnit.MILLISECONDS,
+ TimeUnit.SECONDS);
+
+ this.accepts = registry.newMeter(SelectChannelConnector.class,
+ "accepts",
+ port,
+ "connections",
+ TimeUnit.SECONDS);
+
+ this.connects = registry.newMeter(SelectChannelConnector.class,
+ "connects",
+ port,
+ "connections",
+ TimeUnit.SECONDS);
+
+ this.disconnects = registry.newMeter(SelectChannelConnector.class,
+ "disconnects",
+ port,
+ "connections",
+ TimeUnit.SECONDS);
+
+ this.connections = registry.newCounter(SelectChannelConnector.class,
+ "active-connections",
+ port);
+
+ log.info("Metrics enabled");
+
+ super.doStart();
+ }
+
+ // TODO: remove metrics on doStop()
+
+ @Override
+ public void accept(final int acceptorID) throws IOException {
+ super.accept(acceptorID);
+ accepts.mark();
+ }
+
+ @Override
+ protected void connectionOpened(final Connection connection) {
+ connections.inc();
+ super.connectionOpened(connection);
+ connects.mark();
+ }
+
+ @Override
+ protected void connectionClosed(final Connection connection) {
+ super.connectionClosed(connection);
+ disconnects.mark();
+ final long duration = System.currentTimeMillis() - connection.getTimeStamp();
+ this.duration.update(duration, TimeUnit.MILLISECONDS);
+ connections.dec();
+ }
+}
View
48 nexus-client-core-testsuite/src/test/java/org/sonatype/nexus/client/testsuite/UserIT.java
@@ -0,0 +1,48 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.client.testsuite;
+
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+import org.sonatype.nexus.client.core.NexusClient;
+import org.sonatype.nexus.client.core.subsystem.security.Users;
+
+/**
+ * @since 2.5
+ */
+public class UserIT
+ extends NexusClientITSupport
+{
+
+ public UserIT( final String nexusBundleCoordinates )
+ {
+ super( nexusBundleCoordinates );
+ }
+
+ /**
+ * Related to NEXUS-5037 ensure that html escaped passwords(specifically quote character in this case) can be used as credentials.
+ */
+ @Test
+ public void testUserWithSingleQuotePassword()
+ {
+ Users users = client().getSubsystem( Users.class );
+ String password = "\"";
+ users.create( "test" ).withPassword( password ).withRole( "nx-admin" ).withEmail( "no@where.com" ).save();
+ NexusClient client = createNexusClient( nexus(), "test", password );
+ //will fail if can't authenticate
+ assertThat( client.getNexusStatus(), is( notNullValue() ) );
+ }
+}
View
85 nexus-client-core/src/main/java/org/sonatype/nexus/client/internal/util/Version.java
@@ -0,0 +1,85 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.client.internal.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.io.Closeables;
+
+/**
+ * Helper static methods for reading Maven properties file to get the version from it.
+ *
+ * @author cstamas
+ * @since 2.5.0
+ */
+public class Version
+{
+ private static final Logger LOG = LoggerFactory.getLogger( Version.class );
+
+ private Version()
+ {
+ // no instances
+ }
+
+ /**
+ * Reads the version from a properties file, the one embedded by Maven into Jar during build.
+ *
+ * @param cl the class loader to be used to load the properties file.
+ * @param path the binary path of the properties file to read from (might have more in case of shaded JAR).
+ * @param defaultVersion the version string to return in case of unsuccessful read of the properties file.
+ * @return the version from the Maven properties file on given path, embedded into JAR.
+ * @since 2.4.1
+ */
+ public static String readVersion( final ClassLoader cl, final String path, final String defaultVersion )
+ {
+ String version = defaultVersion;
+ InputStream is = null;
+ try
+ {
+ final Properties props = new Properties();
+ is = cl.getResourceAsStream( path );
+ if ( is != null )
+ {
+ props.load( is );
+ version = props.getProperty( "version" );
+ }
+ }
+ catch ( IOException e )
+ {
+ LOG.error( "Could not load/read version from " + path, e );
+ }
+ finally
+ {
+ Closeables.closeQuietly( is );
+ }
+ return version;
+ }
+
+ /**
+ * Shorthand method. Reads the version from a properties file using classloader that loaded up this class.
+ *
+ * @param path the binary path of the properties file to read from (might have more in case of shaded JAR).
+ * @param defaultVersion the version string to return in case of unsuccessful read of the properties file.
+ * @return the version from the Maven properties file on given path, embedded into JAR.
+ * @since 2.4.1
+ */
+ public static String readVersion( final String path, final String defaultVersion )
+ {
+ return readVersion( Version.class.getClassLoader(), path, defaultVersion );
+ }
+}
View
11 ...nt-core/src/main/java/org/sonatype/nexus/client/rest/jersey/JerseyNexusClientFactory.java
@@ -14,6 +14,7 @@
import java.net.URI;
import java.util.Set;
+
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
@@ -24,7 +25,6 @@
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.params.ConnRoutePNames;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.CoreProtocolPNames;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,9 +34,11 @@
import org.sonatype.nexus.client.internal.rest.NexusXStreamFactory;
import org.sonatype.nexus.client.internal.rest.XStreamXmlProvider;
import org.sonatype.nexus.client.internal.util.Template;
+import org.sonatype.nexus.client.internal.util.Version;
import org.sonatype.nexus.client.rest.ConnectionInfo;
import org.sonatype.nexus.client.rest.ProxyInfo;
import org.sonatype.nexus.client.rest.UsernamePasswordAuthenticationInfo;
+
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.filter.LoggingFilter;
import com.sun.jersey.api.json.JSONConfiguration;
@@ -110,7 +112,7 @@ protected ApacheHttpClient4 doCreateHttpClientFor( final ConnectionInfo connecti
// set UA
client.getClientHandler().getHttpClient().getParams().setParameter( CoreProtocolPNames.USER_AGENT,
- "Nexus-Client/1.0" );
+ "Nexus-Client/" + discoverClientVersion() );
// NXCM-4547 JERSEY-1293 Enforce proxy setting on httpclient
enforceProxyUri( config, client );
@@ -123,6 +125,11 @@ protected ApacheHttpClient4 doCreateHttpClientFor( final ConnectionInfo connecti
return client;
}
+ protected String discoverClientVersion()
+ {
+ return Version.readVersion( "META-INF/maven/org.sonatype.nexus.client/nexus-client-core/pom.properties", "unknown" );
+ }
+
// ==
/**
View
2 ...tered-resources/META-INF/maven/org.sonatype.nexus.client/nexus-client-core/pom.properties
@@ -0,0 +1,2 @@
+# test
+version=${project.version}
View
64 ...c/test/java/org/sonatype/nexus/client/rest/jersey/JerseyNexusTestClientUserAgentTest.java
@@ -0,0 +1,64 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.client.rest.jersey;
+
+import java.net.MalformedURLException;
+
+import junit.framework.Assert;
+
+import org.apache.http.params.CoreProtocolPNames;
+import org.junit.Test;
+import org.sonatype.nexus.client.core.NexusClient;
+import org.sonatype.nexus.client.internal.util.Version;
+import org.sonatype.nexus.client.rest.BaseUrl;
+import org.sonatype.nexus.client.rest.NexusClientFactory;
+
+import com.sun.jersey.client.apache4.ApacheHttpClient4;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.notNullValue;
+
+/**
+ * UT for NexusClient UA, as it should carry the version from now on.
+ *
+ * @author cstamas
+ * @since 2.5
+ */
+public class JerseyNexusTestClientUserAgentTest
+ extends JerseyNexusClientTestSupport
+{
+ @Test
+ public void checkUAVersionIsProperlyReadAndSet()
+ throws MalformedURLException
+ {
+ final String version =
+ Version.readVersion( "META-INF/maven/org.sonatype.nexus.client/nexus-client-core/pom.properties", "foo" );
+ assertThat( "Version read must not return null!", version, notNullValue() );
+ assertThat( "Version read must not return the default (it should succeed in reading the stuff up)!", version,
+ not( equalTo( "foo" ) ) );
+
+ final NexusClientFactory factory = new JerseyNexusClientFactory();
+ final NexusClient client = factory.createFor( BaseUrl.baseUrlFrom( "https://repository.sonatype.org/" ) );
+ Assert.assertNotNull( client.getNexusStatus() );
+ final String userAgent =
+ (String) ( (ApacheHttpClient4) ( (JerseyNexusClient) client ).getClient() ).getClientHandler().getHttpClient().getParams().getParameter(
+ CoreProtocolPNames.USER_AGENT );
+ assertThat( "UA must not be null!", userAgent, notNullValue() );
+ assertThat( "UA must not be empty!", userAgent, containsString( "Nexus-Client" ) );
+ assertThat( "UA should be correct!", userAgent, equalTo( "Nexus-Client/" + version ) );
+ }
+}
View
24 nexus-core/pom.xml
@@ -58,6 +58,10 @@
</dependency>
<dependency>
<groupId>org.sonatype.sisu.goodies</groupId>
+ <artifactId>goodies-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.sonatype.sisu.goodies</groupId>
<artifactId>goodies-eventbus</artifactId>
</dependency>
<dependency>
@@ -253,8 +257,24 @@
</dependency>
<dependency>
- <groupId>org.javasimon</groupId>
- <artifactId>javasimon-core</artifactId>
+ <groupId>com.yammer.metrics</groupId>
+ <artifactId>metrics-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.yammer.metrics</groupId>
+ <artifactId>metrics-guice</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>com.yammer.metrics</groupId>
+ <artifactId>metrics-httpclient</artifactId>
</dependency>
<!-- Testing -->
View
10 nexus-core/src/main/java/org/sonatype/nexus/AbstractApplicationStatusSource.java
@@ -71,7 +71,7 @@ protected ReadWriteLock getLock()
// ==
/**
- * Returns the SystemStatus, guaranteeing it's consistent state.
+ * Returns the SystemStatus, guaranteeing its consistent state.
*/
public SystemStatus getSystemStatus()
{
@@ -91,6 +91,14 @@ public SystemStatus getSystemStatus()
}
}
+ /**
+ * Force an update of SystemStatus.
+ */
+ public void updateSystemStatus()
+ {
+ updateSystemStatusIfNeeded( true );
+ }
+
public boolean setState( SystemState state )
{
Lock lock = getLock().writeLock();
View
3 nexus-core/src/main/java/org/sonatype/nexus/apachehttpclient/Hc4ProviderBase.java
@@ -255,9 +255,8 @@ protected void configureProxy( final DefaultHttpClient httpClient, final RemoteP
* Sub-classed here to customize the http processor and to keep a sane logger name.
*/
private static class DefaultHttpClientImpl
- extends DefaultHttpClient
+ extends InstrumentedHttpClient
{
-
private DefaultHttpClientImpl( final ClientConnectionManager conman, final HttpParams params )
{
super( conman, params );
View
3 nexus-core/src/main/java/org/sonatype/nexus/apachehttpclient/Hc4ProviderImpl.java
@@ -18,6 +18,7 @@
import javax.inject.Named;
import javax.inject.Singleton;
+import com.yammer.metrics.httpclient.InstrumentedClientConnManager;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.conn.ClientConnectionOperator;
import org.apache.http.conn.scheme.PlainSocketFactory;
@@ -269,7 +270,7 @@ protected PoolingClientConnectionManager createClientConnectionManager(
schemeRegistry.register( new Scheme( "http", 80, PlainSocketFactory.getSocketFactory() ) );
schemeRegistry.register( new Scheme( "https", 443, SSLSocketFactory.getSocketFactory() ) );
- final PoolingClientConnectionManager connManager = new PoolingClientConnectionManager( schemeRegistry )
+ final PoolingClientConnectionManager connManager = new InstrumentedClientConnManager( schemeRegistry )
{
@Override
protected ClientConnectionOperator createConnectionOperator( final SchemeRegistry defaultSchemeRegistry )
View
86 nexus-core/src/main/java/org/sonatype/nexus/apachehttpclient/InstrumentedHttpClient.java
@@ -0,0 +1,86 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.apachehttpclient;
+
+import com.yammer.metrics.Metrics;
+import com.yammer.metrics.core.MetricsRegistry;
+import com.yammer.metrics.httpclient.InstrumentedClientConnManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.client.*;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ConnectionKeepAliveStrategy;
+import org.apache.http.conn.routing.HttpRoutePlanner;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpProcessor;
+import org.apache.http.protocol.HttpRequestExecutor;
+
+// NOTE: Duplicated and augmented from original 2.2.0 source to change signature of CTOR ClientConnectionManager parameter
+// NOTE: Should get this changes into metrics-httpclient and avoid needing this
+
+public class InstrumentedHttpClient extends DefaultHttpClient {
+ private final Log log = LogFactory.getLog(getClass());
+
+ private final MetricsRegistry registry;
+
+ public InstrumentedHttpClient(MetricsRegistry registry,
+ ClientConnectionManager manager,
+ HttpParams params) {
+ super(manager, params);
+ this.registry = registry;
+ }
+
+ public InstrumentedHttpClient(ClientConnectionManager manager, HttpParams params) {
+ this(Metrics.defaultRegistry(), manager, params);
+ }
+
+ public InstrumentedHttpClient(HttpParams params) {
+ this(new InstrumentedClientConnManager(), params);
+ }
+
+ public InstrumentedHttpClient() {
+ this(null);
+ }
+
+ @Override
+ protected RequestDirector createClientRequestDirector(HttpRequestExecutor requestExec,
+ ClientConnectionManager conman,
+ ConnectionReuseStrategy reustrat,
+ ConnectionKeepAliveStrategy kastrat,
+ HttpRoutePlanner rouplan,
+ HttpProcessor httpProcessor,
+ HttpRequestRetryHandler retryHandler,
+ RedirectStrategy redirectStrategy,
+ AuthenticationStrategy targetAuthStrategy,
+ AuthenticationStrategy proxyAuthStrategy,
+ UserTokenHandler userTokenHandler,
+ HttpParams params) {
+ return new InstrumentedRequestDirector(
+ registry,
+ log,
+ requestExec,
+ conman,
+ reustrat,
+ kastrat,
+ rouplan,
+ httpProcessor,
+ retryHandler,
+ redirectStrategy,
+ targetAuthStrategy,
+ proxyAuthStrategy,
+ userTokenHandler,
+ params);
+ }
+}
View
128 ...s-core/src/main/java/org/sonatype/nexus/apachehttpclient/InstrumentedRequestDirector.java
@@ -0,0 +1,128 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.apachehttpclient;
+
+import com.yammer.metrics.core.MetricsRegistry;
+import com.yammer.metrics.core.Timer;
+import com.yammer.metrics.core.TimerContext;
+import org.apache.commons.logging.Log;
+import org.apache.http.*;
+import org.apache.http.client.*;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ConnectionKeepAliveStrategy;
+import org.apache.http.conn.routing.HttpRoutePlanner;
+import org.apache.http.impl.client.DefaultRequestDirector;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpProcessor;
+import org.apache.http.protocol.HttpRequestExecutor;
+
+import java.io.IOException;
+
+// NOTE: Duplicated and unchanged from original 2.2.0 source to support change in InstrumentedHttpClient
+// NOTE: Should get this changes into metrics-httpclient and avoid needing this
+
+class InstrumentedRequestDirector
+ extends DefaultRequestDirector {
+ private final static String GET = "GET", POST = "POST", HEAD = "HEAD", PUT = "PUT",
+ OPTIONS = "OPTIONS", DELETE = "DELETE", TRACE = "TRACE",
+ CONNECT = "CONNECT", MOVE = "MOVE", PATCH = "PATCH";
+
+ private final Timer getTimer;
+ private final Timer postTimer;
+ private final Timer headTimer;
+ private final Timer putTimer;
+ private final Timer deleteTimer;
+ private final Timer optionsTimer;
+ private final Timer traceTimer;
+ private final Timer connectTimer;
+ private final Timer moveTimer;
+ private final Timer patchTimer;
+ private final Timer otherTimer;
+
+ InstrumentedRequestDirector(MetricsRegistry registry,
+ Log log,
+ HttpRequestExecutor requestExec,
+ ClientConnectionManager conman,
+ ConnectionReuseStrategy reustrat,
+ ConnectionKeepAliveStrategy kastrat,
+ HttpRoutePlanner rouplan,
+ HttpProcessor httpProcessor,
+ HttpRequestRetryHandler retryHandler,
+ RedirectStrategy redirectStrategy,
+ AuthenticationStrategy targetAuthStrategy,
+ AuthenticationStrategy proxyAuthStrategy,
+ UserTokenHandler userTokenHandler,
+ HttpParams params) {
+ super(log,
+ requestExec,
+ conman,
+ reustrat,
+ kastrat,
+ rouplan,
+ httpProcessor,
+ retryHandler,
+ redirectStrategy,
+ targetAuthStrategy,
+ proxyAuthStrategy,
+ userTokenHandler,
+ params);
+ getTimer = registry.newTimer(HttpClient.class, "get-requests");
+ postTimer = registry.newTimer(HttpClient.class, "post-requests");
+ headTimer = registry.newTimer(HttpClient.class, "head-requests");
+ putTimer = registry.newTimer(HttpClient.class, "put-requests");
+ deleteTimer = registry.newTimer(HttpClient.class, "delete-requests");
+ optionsTimer = registry.newTimer(HttpClient.class, "options-requests");
+ traceTimer = registry.newTimer(HttpClient.class, "trace-requests");
+ connectTimer = registry.newTimer(HttpClient.class, "connect-requests");
+ moveTimer = registry.newTimer(HttpClient.class, "move-requests");
+ patchTimer = registry.newTimer(HttpClient.class, "patch-requests");
+ otherTimer = registry.newTimer(HttpClient.class, "other-requests");
+ }
+
+ @Override
+ public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws HttpException, IOException {
+ final TimerContext timerContext = timer(request).time();
+ try {
+ return super.execute(target, request, context);
+ } finally {
+ timerContext.stop();
+ }
+ }
+
+ private Timer timer(HttpRequest request) {
+ final String method = request.getRequestLine().getMethod();
+ if (GET.equalsIgnoreCase(method)) {
+ return getTimer;
+ } else if (POST.equalsIgnoreCase(method)) {
+ return postTimer;
+ } else if (PUT.equalsIgnoreCase(method)) {
+ return putTimer;
+ } else if (HEAD.equalsIgnoreCase(method)) {
+ return headTimer;
+ } else if (DELETE.equalsIgnoreCase(method)) {
+ return deleteTimer;
+ } else if (OPTIONS.equalsIgnoreCase(method)) {
+ return optionsTimer;
+ } else if (TRACE.equalsIgnoreCase(method)) {
+ return traceTimer;
+ } else if (CONNECT.equalsIgnoreCase(method)) {
+ return connectTimer;
+ } else if (PATCH.equalsIgnoreCase(method)) {
+ return patchTimer;
+ } else if (MOVE.equalsIgnoreCase(method)) {
+ return moveTimer;
+ }
+ return otherTimer;
+ }
+}
View
44 nexus-core/src/main/java/org/sonatype/nexus/email/DefaultNexusEmailer.java
@@ -14,6 +14,7 @@
import java.util.List;
+import org.apache.commons.lang.StringUtils;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Startable;
@@ -23,13 +24,15 @@
import org.sonatype.micromailer.EmailerConfiguration;
import org.sonatype.micromailer.MailRequest;
import org.sonatype.micromailer.MailRequestStatus;
+import org.sonatype.micromailer.MailType;
import org.sonatype.micromailer.imp.DefaultMailType;
import org.sonatype.nexus.ApplicationStatusSource;
import org.sonatype.nexus.SystemStatus;
import org.sonatype.nexus.configuration.AbstractConfigurable;
import org.sonatype.nexus.configuration.Configurator;
import org.sonatype.nexus.configuration.CoreConfiguration;
import org.sonatype.nexus.configuration.application.ApplicationConfiguration;
+import org.sonatype.nexus.configuration.application.GlobalRestApiSettings;
import org.sonatype.nexus.configuration.model.CSmtpConfiguration;
import org.sonatype.nexus.configuration.model.CSmtpConfigurationCoreConfiguration;
@@ -52,6 +55,9 @@
private ApplicationConfiguration applicationConfiguration;
@Requirement
+ private GlobalRestApiSettings globalRestApiSettings;
+
+ @Requirement
private ApplicationStatusSource applicationStatusSource;
@Requirement
@@ -105,10 +111,48 @@ public MailRequestStatus sendMail( MailRequest request )
{
request.setFrom( getSMTPSystemEmailAddress() );
}
+
+ prependNexusBaseUrl( request );
return eMailer.sendMail( request );
}
+ /**
+ * Prepend to message body a link to this Nexus instance (base server URL).
+ */
+ private void prependNexusBaseUrl( final MailRequest request )
+ {
+ final String baseNexusUrl = globalRestApiSettings.getBaseUrl();
+ final MailType mailType = eMailer.getMailTypeSource().getMailType( request.getMailTypeId() );
+
+ final StringBuilder messageBody = new StringBuilder().append( "Message from: " );
+
+ if ( mailType != null && mailType.isBodyIsHtml() )
+ {
+ messageBody
+ .append(
+ StringUtils.isNotBlank( baseNexusUrl )
+ ? String.format( "<a href=\"%s\">%s</a>", baseNexusUrl, baseNexusUrl )
+ : "<i>(Set the Base URL parameter in Nexus Server Administration to include in future emails)</i>"
+ )
+ .append( "<br><br>" );
+ }
+ else
+ {
+ messageBody
+ .append(
+ StringUtils.isNotBlank( baseNexusUrl )
+ ? baseNexusUrl
+ : "(Set the Base URL parameter in Nexus Server Administration to include in future emails)"
+ )
+ .append( "\n\n" );
+ }
+
+ messageBody.append( request.getBodyContext().get( DefaultMailType.BODY_KEY ) );
+
+ request.getBodyContext().put( DefaultMailType.BODY_KEY, messageBody.toString() );
+ }
+
// ==
@Override
View
60 nexus-core/src/main/java/org/sonatype/nexus/formfields/RepoTargetComboFormField.java
@@ -0,0 +1,60 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.formfields;
+
+/**
+ * The model for a combo field allowing for selection of Repository Targets.
+ *
+ * @since 2.5
+ */
+public class RepoTargetComboFormField
+ extends AbstractFormField<String>
+{
+
+ public static final String DEFAULT_HELP_TEXT = "Select the repository target to apply ";
+
+ public static final String DEFAULT_LABEL = "Repository Target";
+
+ public RepoTargetComboFormField( String id, String label, String helpText, boolean required,
+ String regexValidation )
+ {
+ super( id, label, helpText, required, regexValidation );
+ }
+
+ public RepoTargetComboFormField( String id, String label, String helpText, boolean required )
+ {
+ super( id, label, helpText, required );
+ }
+
+ public RepoTargetComboFormField( String id, boolean required )
+ {
+ super( id, DEFAULT_LABEL, DEFAULT_HELP_TEXT, required );
+ }
+
+ public RepoTargetComboFormField( String id )
+ {
+ super( id, DEFAULT_LABEL, DEFAULT_HELP_TEXT, false );
+ }
+
+ public String getType()
+ {
+ return "repo-target";
+ }
+
+ public RepoTargetComboFormField withInitialValue( final String initialValue )
+ {
+ setInitialValue( initialValue );
+ return this;
+ }
+
+}
View
57 nexus-core/src/main/java/org/sonatype/nexus/guice/AbstractInterceptorModule.java
@@ -0,0 +1,57 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+
+package org.sonatype.nexus.guice;
+
+import java.lang.reflect.Method;
+
+import org.aopalliance.intercept.MethodInterceptor;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Key;
+import com.google.inject.matcher.Matcher;
+import com.google.inject.name.Names;
+
+/**
+ * Workaround to automatically share method interceptors until
+ * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=403108">proper Sisu feature</a> is implemented.
+ *
+ * <p>
+ * This module is only bound once in its originating realm, when the bindInterceptor method is first called. The Nexus
+ * Plugin Manager can then see this module via the injected dynamic list of AbstractInterceptorModules and will install
+ * it in any plugins registered after this point.
+ *
+ * <p>
+ * Note: you can't contribute interceptors to earlier plugins or from a plugin to core, but the other direction works fine.
+ *
+ * @since 2.4
+ */
+public abstract class AbstractInterceptorModule
+ extends AbstractModule
+{
+ private boolean bound;
+
+ @Override
+ protected void bindInterceptor( final Matcher<? super Class<?>> classMatcher,
+ final Matcher<? super Method> methodMatcher,
+ final MethodInterceptor... interceptors )
+ {
+ if ( !bound )
+ {
+ // Explicitly bind module instance under a specific sub-type (not Module as Guice forbids that)
+ bind( Key.get( AbstractInterceptorModule.class, Names.named( getClass().getName() ) ) ).toInstance( this );
+ bound = true;
+ }
+ super.bindInterceptor( classMatcher, methodMatcher, interceptors );
+ }
+}
View
37 nexus-core/src/main/java/org/sonatype/nexus/guice/FilterChainModule.java
@@ -0,0 +1,37 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+
+package org.sonatype.nexus.guice;
+
+import org.sonatype.nexus.security.FilterChain;
+import com.google.inject.AbstractModule;
+import com.google.inject.name.Names;
+
+/**
+ * Support module for configuring {@link FilterChain}s.
+ *
+ * @since 2.5
+ */
+public abstract class FilterChainModule
+ extends AbstractModule
+{
+
+ protected void addFilterChain( final String pathPattern, final String filterExpression )
+ {
+ bind( FilterChain.class )
+ .annotatedWith( Names.named( pathPattern ) )
+ .toInstance( new FilterChain( pathPattern, filterExpression )
+ );
+ }
+
+}
View
4 nexus-core/src/main/java/org/sonatype/nexus/guice/NexusModules.java
@@ -14,8 +14,8 @@
package org.sonatype.nexus.guice;
import com.google.inject.AbstractModule;
+import com.yammer.metrics.guice.InstrumentationModule;
import org.apache.shiro.guice.aop.ShiroAopModule;
-import org.sonatype.nexus.timing.TimingModule;
/**
* Nexus guice modules.
@@ -33,7 +33,7 @@
@Override
protected void configure() {
install(new ShiroAopModule());
- install(new TimingModule());
+ install(new InstrumentationModule());
}
}
View
84 ...ore/src/main/java/org/sonatype/nexus/maven/tasks/AbstractFileDeletingWalkerProcessor.java
@@ -0,0 +1,84 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.maven.tasks;
+
+import org.sonatype.nexus.proxy.IllegalOperationException;
+import org.sonatype.nexus.proxy.ItemNotFoundException;
+import org.sonatype.nexus.proxy.ResourceStoreRequest;
+import org.sonatype.nexus.proxy.StorageException;
+import org.sonatype.nexus.proxy.item.StorageCollectionItem;
+import org.sonatype.nexus.proxy.item.StorageItem;
+import org.sonatype.nexus.proxy.maven.MavenRepository;
+import org.sonatype.nexus.proxy.storage.UnsupportedStorageOperationException;
+import org.sonatype.nexus.proxy.walker.AbstractWalkerProcessor;
+import org.sonatype.nexus.proxy.walker.WalkerContext;
+import org.sonatype.nexus.proxy.wastebasket.DeleteOperation;
+
+/**
+ * Common utility methods for WalkerProcessor implementations that perform
+ * file delete operations as part of their processing.
+ *
+ * @since 2.5
+ */
+public abstract class AbstractFileDeletingWalkerProcessor extends AbstractWalkerProcessor
+{
+
+ /**
+ * Inspect the given collection and delete it from the repository if it no longer has any files.
+ */
+ protected void removeDirectoryIfEmpty( MavenRepository repository, StorageCollectionItem coll )
+ throws StorageException, IllegalOperationException, UnsupportedStorageOperationException
+ {
+ try
+ {
+ if ( repository.list( false, coll ).size() > 0 )
+ {
+ return;
+ }
+ // directory is empty, never move to trash
+ repository.deleteItem( false, createResourceStoreRequest( coll, DeleteOperation.DELETE_PERMANENTLY ) );
+ }
+ catch ( ItemNotFoundException e )
+ {
+ // silent, this happens if whole GAV is removed and the dir is removed too
+ }
+ }
+
+ /**
+ * Create a request to delete an item.
+ */
+ protected ResourceStoreRequest createResourceStoreRequest( final StorageItem item, final WalkerContext ctx )
+ {
+ ResourceStoreRequest request = new ResourceStoreRequest( item );
+
+ if ( ctx.getContext().containsKey( DeleteOperation.DELETE_OPERATION_CTX_KEY ) )
+ {
+ request.getRequestContext().put( DeleteOperation.DELETE_OPERATION_CTX_KEY,
+ ctx.getContext().get( DeleteOperation.DELETE_OPERATION_CTX_KEY ) );
+ }
+
+ return request;
+ }
+
+ /**
+ * Create a request to delete an item with the specified DeleteOperation.
+ */
+ protected ResourceStoreRequest createResourceStoreRequest( final StorageCollectionItem item,
+ final DeleteOperation operation )
+ {
+ ResourceStoreRequest request = new ResourceStoreRequest( item );
+ request.getRequestContext().put( DeleteOperation.DELETE_OPERATION_CTX_KEY, operation );
+ return request;
+ }
+
+}
View
413 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/DefaultReleaseRemover.java
@@ -0,0 +1,413 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.maven.tasks;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.sonatype.nexus.maven.tasks.descriptors.ReleaseRemovalTaskDescriptor.ID;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.sonatype.nexus.logging.AbstractLoggingComponent;
+import org.sonatype.nexus.maven.tasks.descriptors.ReleaseRemovalTaskDescriptor;
+import org.sonatype.nexus.proxy.IllegalOperationException;
+import org.sonatype.nexus.proxy.ItemNotFoundException;
+import org.sonatype.nexus.proxy.NoSuchRepositoryException;
+import org.sonatype.nexus.proxy.ResourceStoreRequest;
+import org.sonatype.nexus.proxy.StorageException;
+import org.sonatype.nexus.proxy.item.StorageCollectionItem;
+import org.sonatype.nexus.proxy.item.StorageFileItem;
+import org.sonatype.nexus.proxy.item.StorageItem;
+import org.sonatype.nexus.proxy.maven.MavenRepository;
+import org.sonatype.nexus.proxy.maven.RepositoryPolicy;
+import org.sonatype.nexus.proxy.maven.gav.Gav;
+import org.sonatype.nexus.proxy.maven.version.GenericVersionParser;
+import org.sonatype.nexus.proxy.maven.version.InvalidVersionSpecificationException;
+import org.sonatype.nexus.proxy.maven.version.Version;
+import org.sonatype.nexus.proxy.maven.version.VersionParser;
+import org.sonatype.nexus.proxy.registry.ContentClass;
+import org.sonatype.nexus.proxy.registry.RepositoryRegistry;
+import org.sonatype.nexus.proxy.repository.GroupRepository;
+import org.sonatype.nexus.proxy.repository.ProxyRepository;
+import org.sonatype.nexus.proxy.repository.Repository;
+import org.sonatype.nexus.proxy.target.Target;
+import org.sonatype.nexus.proxy.target.TargetRegistry;
+import org.sonatype.nexus.proxy.target.TargetStoreWalkerFilter;
+import org.sonatype.nexus.proxy.walker.ConjunctionWalkerFilter;
+import org.sonatype.nexus.proxy.walker.DefaultWalkerContext;
+import org.sonatype.nexus.proxy.walker.DottedStoreWalkerFilter;
+import org.sonatype.nexus.proxy.walker.Walker;
+import org.sonatype.nexus.proxy.walker.WalkerContext;
+import org.sonatype.nexus.proxy.walker.WalkerFilter;
+import org.sonatype.nexus.proxy.wastebasket.DeleteOperation;
+import org.sonatype.scheduling.TaskUtil;
+
+/**
+ * @since 2.5
+ */
+@Named
+@Singleton
+public class DefaultReleaseRemover
+ extends AbstractLoggingComponent
+ implements ReleaseRemover
+{
+
+ private final RepositoryRegistry repositoryRegistry;
+
+ private final TargetRegistry targetRegistry;
+
+ private final Walker walker;
+
+ private final ContentClass maven2ContentClass;
+
+ private final VersionParser versionScheme = new GenericVersionParser();
+
+ @Inject
+ public DefaultReleaseRemover( final RepositoryRegistry repositoryRegistry, final TargetRegistry targetRegistry,
+ final Walker walker,
+ final @Named( "maven2" ) ContentClass maven2ContentClass )
+ {
+ this.repositoryRegistry = checkNotNull( repositoryRegistry );
+ this.targetRegistry = checkNotNull(targetRegistry);
+ this.walker = checkNotNull( walker );
+ this.maven2ContentClass = checkNotNull( maven2ContentClass );
+ }
+
+ @Override
+ public ReleaseRemovalResult removeReleases( final ReleaseRemovalRequest request )
+ throws NoSuchRepositoryException
+ {
+ logDetails( request );
+ ReleaseRemovalResult result = new ReleaseRemovalResult( request.getRepositoryId() );
+
+ Repository repository = repositoryRegistry.getRepository( request.getRepositoryId() );
+ Target repositoryTarget = targetRegistry.getRepositoryTarget( request.getTargetId() );
+
+ if ( !Strings.isNullOrEmpty( request.getTargetId() ) && repositoryTarget == null )
+ {
+ throw new IllegalStateException(
+ "The specified repository target does not exist. Perhaps it has been deleted since this repository target was configured? Target id = "
+ + request.getTargetId() );
+ }
+
+ if ( !process( request, result, repository, repositoryTarget ) )
+ {
+ throw new IllegalArgumentException( "The repository with ID=" + repository.getId() + " is not valid for "
+ + ID );
+ }
+ getLogger().debug( "Results of {} are: {}", ReleaseRemovalTaskDescriptor.ID, result );
+ return result;
+ }
+
+ private boolean process( final ReleaseRemovalRequest request, final ReleaseRemovalResult result,
+ final Repository repository, final Target repositoryTarget )
+ {
+ if ( !repository.getRepositoryContentClass().isCompatible( maven2ContentClass ) )
+ {
+ getLogger().debug( "Skipping '{}' is not a maven 2 repository", repository.getId() );
+ return false;
+ }
+
+ if ( !repository.getLocalStatus().shouldServiceRequest() )
+ {
+ getLogger().debug( "Skipping '{}' because the repository is out of service", repository.getId() );
+ return false;
+ }
+
+ if ( repository.getRepositoryKind().isFacetAvailable( ProxyRepository.class ) )
+ {
+ getLogger().debug( "Skipping '{}' because it is a proxy repository", repository.getId() );
+ return false;
+ }
+
+ if ( repository.getRepositoryKind().isFacetAvailable( GroupRepository.class ) )
+ {
+ getLogger().debug( "Skipping '{}' because it is a group repository", repository.getId() );
+ return false;
+ }
+
+ MavenRepository mavenRepository = repository.adaptToFacet( MavenRepository.class );
+
+ if(mavenRepository == null)
+ {
+ getLogger().debug( "Skipping '{}' because it could not be adapted to MavenRepository", repository.getId() );
+ return false;
+ }
+
+ if ( !RepositoryPolicy.RELEASE.equals( mavenRepository.getRepositoryPolicy() ) )
+ {
+ getLogger().debug( "Skipping '{}' because it is a snapshot or mixed repository", repository.getId() );
+ return false;
+ }
+
+ removeReleasesFromMavenRepository( mavenRepository, request, result, repositoryTarget );
+ return true;
+ }
+
+ private void removeReleasesFromMavenRepository( final MavenRepository repository,
+ final ReleaseRemovalRequest request,
+ final ReleaseRemovalResult result,
+ final Target repositoryTarget )
+ {
+ TaskUtil.checkInterruption();
+
+ if ( !repository.getLocalStatus().shouldServiceRequest() )
+ {
+ return;
+ }
+
+ getLogger().debug(
+ "Collecting deletable releases on repository '" + repository.getId() + "' from storage directory "
+ + repository.getLocalUrl() );
+
+ DefaultWalkerContext ctxMain =
+ new DefaultWalkerContext( repository, new ResourceStoreRequest( "/" ),
+ determineFilter( repositoryTarget ) );
+
+ ctxMain.getContext().put( DeleteOperation.DELETE_OPERATION_CTX_KEY, DeleteOperation.MOVE_TO_TRASH );
+
+ ctxMain.getProcessors().add( new ReleaseRemovalWalkerProcessor( repository, request, result, repositoryTarget ) );
+
+ walker.walk( ctxMain );
+
+ if ( ctxMain.getStopCause() != null )
+ {
+ result.setSuccessful( false );
+ }
+ }
+
+ /**
+ * Create an appropriate filter based on the repositoryTarget
+ */
+ private WalkerFilter determineFilter( final Target repositoryTarget )
+ {
+ if ( repositoryTarget == null )
+ {
+ return new DottedStoreWalkerFilter();
+ }
+ return ConjunctionWalkerFilter.satisfiesAllOf( new DottedStoreWalkerFilter(),
+ new TargetStoreWalkerFilter( repositoryTarget ) );
+ }
+
+ private void logDetails( final ReleaseRemovalRequest request )
+ {
+ getLogger().info( "Removing older releases from repository: {}", request.getRepositoryId() );
+ if(getLogger().isDebugEnabled())
+ {
+ getLogger().debug( "With parameters: " );
+ getLogger().debug( " NumberOfVersionsToKeep: {}", request.getNumberOfVersionsToKeep() );
+ getLogger().debug( " RepositoryTarget applied: {}", request.getTargetId() );
+ }
+ }
+
+ private class ReleaseRemovalWalkerProcessor
+ extends AbstractFileDeletingWalkerProcessor
+ {
+
+ private static final String POSSIBLY_EMPTY_COLLECTIONS = "possiblyEmptyCollections";
+
+ private final MavenRepository repository;
+
+ private final ReleaseRemovalRequest request;
+
+ private final Map<Version, List<StorageFileItem>> deletableVersionsAndFiles =
+ new HashMap<Version, List<StorageFileItem>>();
+
+ private final Map<Gav, Map<Version, List<StorageFileItem>>> groupArtifactToVersions =
+ new HashMap<Gav, Map<Version, List<StorageFileItem>>>();
+
+ private final ReleaseRemovalResult result;
+
+ private final Target repositoryTarget;
+
+ private int deletedFiles = 0;
+
+ private ReleaseRemovalWalkerProcessor( final MavenRepository repository,
+ final ReleaseRemovalRequest request, final ReleaseRemovalResult result,
+ final Target repositoryTarget )
+ {
+ this.repository = repository;
+ this.request = request;
+ this.result = result;
+ this.repositoryTarget = repositoryTarget;
+ }
+
+ @Override
+ public void processItem( final WalkerContext context, final StorageItem item )
+ throws Exception
+ {
+ }
+
+ @Override
+ public void onCollectionExit( final WalkerContext context, final StorageCollectionItem coll )
+ throws Exception
+ {
+ try
+ {
+ doOnCollectionExit( context, coll );
+ }
+ catch ( Exception e )
+ {
+ // we always simply log the exception and continue
+ getLogger().warn( "{} failed to process path: '{}'.", ID, coll.getPath(), e );
+ }
+ }
+
+ private void doOnCollectionExit( final WalkerContext context, final StorageCollectionItem coll )
+ throws ItemNotFoundException, StorageException, IllegalOperationException,
+ InvalidVersionSpecificationException
+ {
+ deletableVersionsAndFiles.clear();
+
+ Collection<StorageItem> items = repository.list( false, coll );
+ Gav gav = null;
+ for ( StorageItem item : items )
+ {
+ if ( !item.isVirtual() && !StorageCollectionItem.class.isAssignableFrom( item.getClass() ) )
+ {
+ gav =
+ ( (MavenRepository) coll.getRepositoryItemUid().getRepository() ).getGavCalculator().pathToGav(
+ item.getPath() );
+ if ( gav != null )
+ {
+ addCollectionToContext( context, coll );
+
+ maybeAddStorageFileItemToMap( gav, (StorageFileItem) item );
+ }
+ }
+ }
+ // if a gav can be calculated, it should be shared by all files in the collection
+ if ( null != gav )
+ {
+ groupVersions( groupArtifactToVersions, deletableVersionsAndFiles, gav );
+ }
+ }
+
+ /**
+ * Compare the item path to the RepositoryTarget(if it is declared) and only include files that match that pattern.
+ * While the walker itself handles GAV paths, this ensures that we also respect patterns with file-level granularity.
+ */
+ private void maybeAddStorageFileItemToMap( final Gav gav, final StorageFileItem item )
+ {
+ if ( repositoryTarget != null && !repositoryTarget.isPathContained(
+ item.getRepositoryItemUid().getRepository().getRepositoryContentClass(), item
+ .getPath() ) )
+ {
+ getLogger().debug( "Excluding file: {} from deletion due to repositoryTarget: {}.", item.getName(), repositoryTarget.getName() );
+ return;
+ }
+ addStorageFileItemToMap( deletableVersionsAndFiles, gav, (StorageFileItem) item );
+ }
+
+ /**
+ * Store visited collections so we can later determine if we need to delete them.
+ */
+ private void addCollectionToContext( final WalkerContext context, final StorageCollectionItem coll )
+ {
+ if ( !context.getContext().containsKey( POSSIBLY_EMPTY_COLLECTIONS ) )
+ {
+ context.getContext().put( POSSIBLY_EMPTY_COLLECTIONS, Lists.<StorageCollectionItem>newArrayList() );
+ }
+ ( (List<StorageCollectionItem>) context.getContext().get( POSSIBLY_EMPTY_COLLECTIONS ) ).add( coll );
+ }
+
+ /**
+ * Map Group + Artifact to each version with those GA coordinates
+ */
+ private void groupVersions( final Map<Gav, Map<Version, List<StorageFileItem>>> groupArtifactToVersions,
+ final Map<Version, List<StorageFileItem>> versionsAndFiles,
+ final Gav gav )
+ {
+ //ga only coordinates
+ Gav ga = new Gav( gav.getGroupId(), gav.getArtifactId(), "" );
+ if ( !groupArtifactToVersions.containsKey( ga ) )
+ {
+ groupArtifactToVersions.put( ga, Maps.newHashMap( versionsAndFiles ) );
+ }
+ groupArtifactToVersions.get( ga ).putAll( versionsAndFiles );
+ }
+
+ protected void addStorageFileItemToMap( Map<Version, List<StorageFileItem>> map, Gav gav, StorageFileItem item )
+ {
+ Version key = null;
+ try
+ {
+ key = versionScheme.parseVersion( gav.getVersion() );
+ }
+ catch ( InvalidVersionSpecificationException e )
+ {
+ throw new IllegalStateException( "Unable to determine version for " + gav.getVersion() +
+ ", cannot proceed with deletion of releases unless"
+ + "all version information can be parsed into major.minor.incremental version." );
+ }
+
+ if ( !map.containsKey( key ) )
+ {
+ map.put( key, new ArrayList<StorageFileItem>() );
+ }
+
+ map.get( key ).add( item );
+ }
+
+ @Override
+ public void afterWalk( final WalkerContext context )
+ throws Exception
+ {
+ for ( Map.Entry<Gav, Map<Version, List<StorageFileItem>>> gavListEntry : groupArtifactToVersions.entrySet() )
+ {
+ Map<Version, List<StorageFileItem>> versions = gavListEntry.getValue();
+ if ( versions.size() > request.getNumberOfVersionsToKeep() )
+ {
+ getLogger().debug( "{} will delete {} versions of artifact with g={} a={}",
+ ReleaseRemovalTaskDescriptor.ID,
+ versions.size() - request.getNumberOfVersionsToKeep(),
+ gavListEntry.getKey().getGroupId(), gavListEntry.getKey().getArtifactId() );
+
+ List<Version> sortedVersions = Lists.newArrayList( versions.keySet() );
+ Collections.sort( sortedVersions );
+ List<Version> toDelete =
+ sortedVersions.subList( 0, versions.size() - request.getNumberOfVersionsToKeep() );
+ getLogger().debug( "Will delete these specific versions: {}", toDelete );
+ for ( Version version : toDelete )
+ {
+ for ( StorageFileItem storageFileItem : versions.get( version ) )
+ {
+ repository.deleteItem( createResourceStoreRequest( storageFileItem, context ) );
+ deletedFiles++;
+ }
+ }
+ if ( context.getContext().containsKey( POSSIBLY_EMPTY_COLLECTIONS ) )
+ {
+ for ( StorageCollectionItem coll : (List<StorageCollectionItem>) context.getContext().get(
+ POSSIBLY_EMPTY_COLLECTIONS ) )
+ {
+ removeDirectoryIfEmpty( repository, coll );
+ }
+ }
+ }
+ }
+ result.setDeletedFileCount( deletedFiles );
+ result.setSuccessful( true );
+ }
+ }
+}
View
85 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/DefaultSnapshotRemover.java
@@ -16,6 +16,7 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -308,9 +309,11 @@ private void logDetails( SnapshotRemovalRequest request )
}
private class SnapshotRemoverWalkerProcessor
- extends AbstractWalkerProcessor
+ extends AbstractFileDeletingWalkerProcessor
{
+ private static final long MILLIS_IN_A_DAY = 86400000L;
+
private final MavenRepository repository;
private final SnapshotRemovalRequest request;
@@ -325,6 +328,10 @@ private void logDetails( SnapshotRemovalRequest request )
private final long dateThreshold;
+ private final long startTime;
+
+ private final long gracePeriodInMillis;
+
private boolean shouldProcessCollection;
private boolean removeWholeGAV;
@@ -340,16 +347,20 @@ public SnapshotRemoverWalkerProcessor( MavenRepository repository, SnapshotRemov
this.request = request;
this.collectionNodes = collectionNodes;
+ this.startTime = System.currentTimeMillis();
+
int days = request.getRemoveSnapshotsOlderThanDays();
if ( days > 0 )
{
- this.dateThreshold = System.currentTimeMillis() - ( days * 86400000L );
+ this.dateThreshold = startTime - ( days * MILLIS_IN_A_DAY );
}
else
{
this.dateThreshold = -1;
}
+
+ gracePeriodInMillis = Math.max( 0, request.getGraceDaysAfterRelease() ) * MILLIS_IN_A_DAY;
}
protected void addStorageFileItemToMap( Map<Version, List<StorageFileItem>> map, Gav gav, StorageFileItem item )
@@ -473,8 +484,8 @@ public void doOnCollectionExit( WalkerContext context, StorageCollectionItem col
{
getLogger().debug( "itemTimestamp=" + itemTimestamp + ", dateTreshold=" + dateThreshold );
- // if dateTreshold is not used (zero days) OR
- // if itemTimestamp is less then dateTreshold (NB: both are positive!)
+ // if dateThreshold is not used (zero days) OR
+ // if itemTimestamp is less then dateThreshold (NB: both are positive!)
// below will the retentionCount overrule if needed this
if ( -1 == dateThreshold || itemTimestamp < dateThreshold )
{
@@ -595,9 +606,12 @@ public void doOnCollectionExit( WalkerContext context, StorageCollectionItem col
}
catch ( ItemNotFoundException e )
{
- if ( getLogger().isDebugEnabled() )
+ // NEXUS-5682 Since checksum files are no longer physically represented on the file system,
+ // it is expected that they will generate ItemNotFoundException. Log at trace level only for
+ // diagnostic purposes.
+ if ( getLogger().isTraceEnabled() )
{
- getLogger().debug( "Could not delete file:", e );
+ getLogger().trace( "Could not delete file:", e );
}
}
catch ( Exception e )
@@ -608,7 +622,7 @@ public void doOnCollectionExit( WalkerContext context, StorageCollectionItem col
}
}
- removeDirectoryIfEmpty( coll );
+ removeDirectoryIfEmpty( repository, coll );
updateMetadataIfNecessary( context, coll );
@@ -628,33 +642,10 @@ private void updateMetadataIfNecessary( WalkerContext context, StorageCollection
}
}
- private void removeDirectoryIfEmpty( StorageCollectionItem coll )
- throws StorageException, IllegalOperationException, UnsupportedStorageOperationException
- {
- try
- {
- if ( repository.list( false, coll ).size() > 0 )
- {
- return;
- }
-
- if ( getLogger().isDebugEnabled() )
- {
- getLogger().debug(
- "Removing the empty directory leftover: UID=" + coll.getRepositoryItemUid().toString() );
- }
-
- // directory is empty, never move to trash
- repository.deleteItem( false, createResourceStoreRequest( coll, DeleteOperation.DELETE_PERMANENTLY ) );
- }
- catch ( ItemNotFoundException e )
- {
- // silent, this happens if whole GAV is removed and the dir is removed too
- }
- }
-
public boolean releaseExistsForSnapshot( Gav snapshotGav, Map<String, Object> context )
{
+ long releaseTimestamp = -1;
+
for ( Repository repository : repositoryRegistry.getRepositories() )
{
// we need to filter for:
@@ -705,9 +696,11 @@ public boolean releaseExistsForSnapshot( Gav snapshotGav, Map<String, Object> co
getLogger().debug( "Checking for release counterpart in repository '{}' and path '{}'",
mrepository.getId(), req.toString() );
- mrepository.retrieveItem( false, req );
+ final StorageItem item = mrepository.retrieveItem( false, req );
- return true;
+ releaseTimestamp = item.getCreated();
+
+ break;
}
catch ( ItemNotFoundException e )
{
@@ -722,28 +715,8 @@ public boolean releaseExistsForSnapshot( Gav snapshotGav, Map<String, Object> co
}
}
- return false;
- }
-
- private ResourceStoreRequest createResourceStoreRequest( final StorageItem item, final WalkerContext ctx )
- {
- ResourceStoreRequest request = new ResourceStoreRequest( item );
-
- if ( ctx.getContext().containsKey( DeleteOperation.DELETE_OPERATION_CTX_KEY ) )
- {
- request.getRequestContext().put( DeleteOperation.DELETE_OPERATION_CTX_KEY,
- ctx.getContext().get( DeleteOperation.DELETE_OPERATION_CTX_KEY ) );
- }
-
- return request;
- }
-
- private ResourceStoreRequest createResourceStoreRequest( final StorageCollectionItem item,
- final DeleteOperation operation )
- {
- ResourceStoreRequest request = new ResourceStoreRequest( item );
- request.getRequestContext().put( DeleteOperation.DELETE_OPERATION_CTX_KEY, operation );
- return request;
+ return releaseTimestamp == 0 // 0 when item creation day is unknown
+ || ( releaseTimestamp > 0 && startTime > releaseTimestamp + gracePeriodInMillis );
}
public int getDeletedSnapshots()
View
57 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/ReleaseRemovalRequest.java
@@ -0,0 +1,57 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.maven.tasks;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Encapsulate parameters to {@link ReleaseRemover}
+ *
+ * @since 2.5
+ */
+public class ReleaseRemovalRequest
+{
+ private final String repositoryId;
+
+ private final int numberOfVersionsToKeep;
+
+ private final String targetId;
+
+ /**
+ *
+ * @param repositoryId the repository to target
+ * @param numberOfVersionsToKeep the number of released versions to keep for Group/Artifact in the repository
+ * @param targetId (optional) Repository Target id to be applied
+ */
+ public ReleaseRemovalRequest( final String repositoryId, final int numberOfVersionsToKeep, final String targetId )
+ {
+ this.repositoryId = checkNotNull(repositoryId);
+ this.numberOfVersionsToKeep = checkNotNull(numberOfVersionsToKeep);
+ this.targetId = targetId;
+ }
+
+ public String getRepositoryId()
+ {
+ return repositoryId;
+ }
+
+ public int getNumberOfVersionsToKeep()
+ {
+ return numberOfVersionsToKeep;
+ }
+
+ public String getTargetId()
+ {
+ return targetId;
+ }
+}
View
69 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/ReleaseRemovalResult.java
@@ -0,0 +1,69 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.maven.tasks;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Simple struct for consolidating results of ReleaseRemoval task.
+ *
+ * @since 2.5
+ */
+public class ReleaseRemovalResult
+{
+ private final String repoId;
+
+ private int deletedFileCount;
+
+ private boolean isSuccessful = false;
+
+ public ReleaseRemovalResult( final String repoId )
+ {
+ this.repoId = checkNotNull(repoId);
+ }
+
+ public String getRepoId()
+ {
+ return repoId;
+ }
+
+ public int getDeletedFileCount()
+ {
+ return deletedFileCount;
+ }
+
+ public void setDeletedFileCount( final int deletedFileCount )
+ {
+ this.deletedFileCount = deletedFileCount;
+ }
+
+ public boolean isSuccessful()
+ {
+ return isSuccessful;
+ }
+
+ public void setSuccessful( final boolean successful )
+ {
+ isSuccessful = successful;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "ReleaseRemovalResult{" +
+ "repoId='" + repoId + '\'' +
+ ", deletedFileCount=" + deletedFileCount +
+ ", isSuccessful=" + isSuccessful +
+ '}';
+ }
+}
View
28 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/ReleaseRemover.java
@@ -0,0 +1,28 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.maven.tasks;
+
+import org.sonatype.nexus.proxy.NoSuchRepositoryException;
+
+/**
+ * @since 2.5.0
+ */
+public interface ReleaseRemover
+{
+
+ /**
+ * Conditionally remove released artifacts from a repository based on the request.
+ */
+ ReleaseRemovalResult removeReleases( ReleaseRemovalRequest request )
+ throws NoSuchRepositoryException;
+}
View
59 nexus-core/src/main/java/org/sonatype/nexus/maven/tasks/ReleaseRemoverTask.java
@@ -0,0 +1,59 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2007-2012 Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.maven.tasks;
+
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.sonatype.nexus.maven.tasks.descriptors.ReleaseRemovalTaskDescriptor;
+import org.sonatype.nexus.scheduling.AbstractNexusRepositoriesTask;
+import org.sonatype.scheduling.SchedulerTask;
+
+/**
+ * @since 2.5
+ */
+@Component( role = SchedulerTask.class, hint = ReleaseRemovalTaskDescriptor.ID, instantiationStrategy = "per-lookup" )
+public class ReleaseRemoverTask extends AbstractNexusRepositoriesTask<ReleaseRemovalResult>
+{
+
+ @Requirement
+ private ReleaseRemover releaseRemover;
+
+ @Override
+ protected String getRepositoryFieldId()
+ {
+ return ReleaseRemovalTaskDescriptor.REPOSITORY_FIELD_ID;
+ }
+
+ @Override
+ protected ReleaseRemovalResult doRun()
+ throws Exception
+ {
+ int numberOfVersionsToKeep = Integer.parseInt(
+ getParameter( ReleaseRemovalTaskDescriptor.NUMBER_OF_VERSIONS_TO_KEEP_FIELD_ID ) );
+ String targetId = getParameter( ReleaseRemovalTaskDescriptor.REPOSITORY_TARGET_FIELD_ID );
+ return releaseRemover.removeReleases(
+ new ReleaseRemovalRequest( getRepositoryId(), numberOfVersionsToKeep, targetId ) );
+ }
+
+ @Override
+ protected String getAction()
+ {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ protected String getMessage()
+ {
+ return "Removing old releases from repository " + getRepositoryName();
+ }