Permalink
Browse files

Merge remote-tracking branch 'origin/master' into squash-o-matic-output

  • Loading branch information...
2 parents 45bf889 + 844a0f6 commit 6cfc724ca2c659e9169d21906c972893143482df @cstamas cstamas committed Dec 11, 2012
@@ -0,0 +1,40 @@
+/*
+ * 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.proxy;
+
+/**
+ * Local storage exception thrown by local storage when stream/content being pushed (stored) ends prematurely (EOFs).
+ * Denotes an unrecoverable state, but is not resolvable by Nexus core (happens when client drops connection
+ * during upload, recovery is to have client retry upload).
+ *
+ * @author cstamas
+ * @since 2.3
+ */
+public class LocalStorageEofException
+ extends LocalStorageException
+{
+ public LocalStorageEofException( String msg )
+ {
+ super( msg );
+ }
+
+ public LocalStorageEofException( String msg, Throwable cause )
+ {
+ super( msg, cause );
+ }
+
+ public LocalStorageEofException( Throwable cause )
+ {
+ super( cause.getMessage(), cause );
+ }
+}
@@ -14,12 +14,12 @@
import static com.google.common.base.Preconditions.checkNotNull;
+import java.io.EOFException;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -31,11 +31,11 @@
import org.codehaus.plexus.util.IOUtil;
import org.sonatype.nexus.logging.AbstractLoggingComponent;
import org.sonatype.nexus.proxy.ItemNotFoundException;
+import org.sonatype.nexus.proxy.LocalStorageEofException;
import org.sonatype.nexus.proxy.LocalStorageException;
import org.sonatype.nexus.proxy.ResourceStoreRequest;
import org.sonatype.nexus.proxy.access.Action;
import org.sonatype.nexus.proxy.item.ContentLocator;
-import org.sonatype.nexus.proxy.item.RepositoryItemUid;
import org.sonatype.nexus.proxy.item.RepositoryItemUidLock;
import org.sonatype.nexus.proxy.item.StorageItem;
import org.sonatype.nexus.proxy.item.uid.IsItemAttributeMetacontentAttribute;
@@ -113,6 +113,17 @@ public void storeItem( final Repository repository, final File repositoryBaseDir
os.flush();
}
+ catch ( EOFException e )
+ {
+ if ( hiddenTarget != null )
+ {
+ hiddenTarget.delete();
+ }
+
+ throw new LocalStorageEofException( String.format(
+ "EOF during storing on path \"%s\" (while writing to hiddenTarget: \"%s\")",
+ item.getRepositoryItemUid().toString(), hiddenTarget.getAbsolutePath() ), e );
+ }
catch ( IOException e )
{
if ( hiddenTarget != null )
@@ -14,8 +14,14 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.emptyIterableOf;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
@@ -41,6 +47,7 @@
import org.sonatype.nexus.proxy.repository.GroupRepository;
import org.sonatype.nexus.proxy.repository.LocalStatus;
import org.sonatype.nexus.proxy.repository.Repository;
+import org.sonatype.nexus.util.WrappingInputStream;
import com.google.common.base.Strings;
@@ -442,6 +449,68 @@ public void testNexus4985GroupsShouldNotSwallowMemberExceptions()
}
}
+ /**
+ * NXCM-4582: When Local storage is about to store something, but during "store" operation source stream EOFs,
+ * the new LocalStorage exception should be thrown, to differentiate from other "fatal" (like disk full or what not)
+ * error.
+ */
+ @Test
+ public void testNXCM4852()
+ throws Exception
+ {
+ final Repository repository = getRepositoryRegistry().getRepository( "inhouse" );
+ ResourceStoreRequest request =
+ new ResourceStoreRequest( "/activemq/activemq-core/1.2/activemq-core-1.2.jar", true );
+
+ try
+ {
+ repository.storeItem( request, new WrappingInputStream(
+ new ByteArrayInputStream( "123456789012345678901234567890".getBytes() ) )
+ {
+ @Override
+ public int read()
+ throws IOException
+ {
+ int result = super.read();
+ if ( result == -1 )
+ {
+ throw new EOFException( "Foo" );
+ }
+ else
+ {
+ return result;
+ }
+ }
+
+ @Override
+ public int read( final byte[] b, final int off, final int len )
+ throws IOException
+ {
+ int result = super.read( b, off, len );
+ if ( result == -1 )
+ {
+ throw new EOFException( "Foo" );
+ }
+ return result;
+ }
+ }, null );
+
+ Assert.fail( "We expected a LocalStorageEofException to be thrown" );
+ }
+ catch ( LocalStorageEofException e )
+ {
+ // good, we expected this
+ }
+ finally
+ {
+ // now we have to ensure no remnant files exists
+ assertThat( repository.getLocalStorage().containsItem( repository, request ), is( false ) );
+ // no tmp files should exists either
+ assertThat( repository.getLocalStorage().listItems( repository, new ResourceStoreRequest( "/.nexus/tmp" ) ), is( empty() ) );
+ }
+ }
+
+
//
protected int countOccurence( final String string, final String snippet )
@@ -13,6 +13,7 @@
package org.sonatype.nexus.rest.indexng;
import java.util.Collection;
+import java.util.Collections;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -21,7 +22,7 @@
class GAHolder
{
- private final SortedMap<StringVersion, NexusNGArtifact> versionHits = new TreeMap<StringVersion, NexusNGArtifact>();
+ private final SortedMap<StringVersion, NexusNGArtifact> versionHits = new TreeMap<StringVersion, NexusNGArtifact>( Collections.reverseOrder() );
private NexusNGArtifact latestSnapshot = null;
@@ -42,15 +43,15 @@ public void putVersionHit( StringVersion version, NexusNGArtifact versionHit )
if ( VersionUtils.isSnapshot( versionHit.getVersion() ) )
{
- if ( latestSnapshotVersion == null || latestSnapshotVersion.compareTo( version ) > 0 )
+ if ( latestSnapshotVersion == null || latestSnapshotVersion.compareTo( version ) < 0 )
{
latestSnapshot = versionHit;
latestSnapshotVersion = version;
}
}
else
{
- if ( latestReleaseVersion == null || latestReleaseVersion.compareTo( version ) > 0 )
+ if ( latestReleaseVersion == null || latestReleaseVersion.compareTo( version ) < 0 )
{
latestRelease = versionHit;
latestReleaseVersion = version;
@@ -55,21 +55,25 @@ Sonatype.SearchStore = function(config) {
},
scope : this
},
+ // FIXME loadexception event is deprecated, should use general DataProxy#exception event
'loadexception' : {
- fn : function (obj, options, response, error) {
- try {
- // The response is already HTML escaped as it's coming through the REST layer, and can be directly used as
- // a warning
- var errorResponse = Ext.decode(response.responseText);
- if ( errorResponse.errors && errorResponse.errors[0] && errorResponse.errors[0].id == "search" ) {
- this.grid.setWarningLabel(errorResponse.errors[0].msg);
- } else {
- this.grid.setWarningLabel(response.responseText);
- }
- } catch (e) {
- Sonatype.MessageBox.alert('Problem parsing error response:\n' + response.responseText);
- }
- },
+ fn : function(obj, options, response) {
+ try {
+ // The response is already HTML escaped as it's coming through the REST layer, and can be directly used as
+ // a warning
+ var errorResponse = Ext.decode(response.responseText);
+ if (errorResponse.errors && errorResponse.errors[0] && errorResponse.errors[0].id === "search") {
+ this.grid.setWarningLabel(errorResponse.errors[0].msg);
+ } else if (typeof response.responseText !== 'undefined') {
+ this.grid.setWarningLabel(response.responseText);
+ } else {
+ this.grid.setWarningLabel('Could not retrieve search results.');
+ }
+ }
+ catch (e) {
+ Sonatype.MessageBox.alert('Problem parsing error response:\n' + e.toString() + '\n' + response.responseText);
+ }
+ },
scope : this
}
}
@@ -262,8 +266,8 @@ Ext.extend(Sonatype.repoServer.SearchResultGrid, Ext.grid.GridPanel, {
latest = record.get('latestSnapshot');
}
- return 'Latest: ' + latest + ' <a href="#nexus-search;gav~' + record.get('groupId') + '~' + record.get('artifactId')
- + '~~~~kw,versionexpand " onmousedown="cancel_bubble(event)" onclick="cancel_bubble(event); return true;">(Show All Versions)</a>';
+ return '<a href="#nexus-search;gav~' + record.get('groupId') + '~' + record.get('artifactId')
+ + '~~~~kw,versionexpand " onmousedown="cancel_bubble(event)" onclick="cancel_bubble(event); return true;">Show All Versions</a>';
},
formatDownloadLinks : function(value, p, record, rowIndex, colIndex, store) {
var hitIndex = 0;
Oops, something went wrong.

0 comments on commit 6cfc724

Please sign in to comment.