Skip to content

Commit

Permalink
Checks for plugin jar file corruption and logs if found.
Browse files Browse the repository at this point in the history
Maintain existing "refuse to start" behaviour.
  • Loading branch information
jimwebber committed Jun 28, 2018
1 parent 5402e1f commit 3c92efe
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.List;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import org.neo4j.collection.PrefetchingRawIterator;
Expand All @@ -48,13 +49,14 @@ public class ProcedureJarLoader
private final ReflectiveProcedureCompiler compiler;
private final Log log;

public ProcedureJarLoader( ReflectiveProcedureCompiler compiler, Log log )
ProcedureJarLoader( ReflectiveProcedureCompiler compiler, Log log )
{
this.compiler = compiler;
this.log = log;
}

public Callables loadProcedures( URL jar ) throws Exception
// TODO: delete me and change the tests
Callables loadProcedures( URL jar ) throws Exception
{
return loadProcedures( jar, new URLClassLoader( new URL[]{jar}, this.getClass().getClassLoader() ),
new Callables() );
Expand All @@ -73,6 +75,8 @@ public Callables loadProceduresFromDir( File root ) throws IOException, KernelEx
.collect( toList() );
URL[] jarFiles = list.toArray( new URL[list.size()] );

validateJarFiles( jarFiles );

URLClassLoader loader = new URLClassLoader( jarFiles, this.getClass().getClassLoader() );

for ( URL jarFile : jarFiles )
Expand All @@ -82,6 +86,22 @@ public Callables loadProceduresFromDir( File root ) throws IOException, KernelEx
return out;
}

private void validateJarFiles( URL[] jarFiles ) throws IOException
{
for ( URL jarFile : jarFiles )
{
try
{
new ZipFile( new File( jarFile.getFile() ) );
}
catch ( IOException e )
{
log.error( String.format( "Plugin jar file: %s corrupted. Please reinstall.", jarFile.getFile() ) );
throw e;
}
}
}

private Callables loadProcedures( URL jar, ClassLoader loader, Callables target )
throws IOException, KernelException
{
Expand Down Expand Up @@ -185,12 +205,12 @@ public List<CallableUserFunction> functions()
return functions;
}

public void addAllProcedures( List<CallableProcedure> callableProcedures )
void addAllProcedures( List<CallableProcedure> callableProcedures )
{
procedures.addAll( callableProcedures );
}

public void addAllFunctions( List<CallableUserFunction> callableFunctions )
void addAllFunctions( List<CallableUserFunction> callableFunctions )
{
functions.addAll( callableFunctions );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,31 @@
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;
import java.util.zip.ZipException;

import org.neo4j.kernel.api.ResourceTracker;
import org.neo4j.kernel.api.StubResourceManager;
import org.neo4j.kernel.api.exceptions.ProcedureException;
import org.neo4j.kernel.api.proc.BasicContext;
import org.neo4j.kernel.api.proc.CallableProcedure;
import org.neo4j.kernel.api.proc.ProcedureSignature;
import org.neo4j.logging.AssertableLogProvider;
import org.neo4j.logging.NullLog;
import org.neo4j.procedure.Name;
import org.neo4j.procedure.Procedure;

import static java.util.stream.Collectors.toList;
import static junit.framework.TestCase.fail;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertThat;
Expand Down Expand Up @@ -202,14 +209,51 @@ public void shouldGiveHelpfulErrorOnGenericStreamProcedure() throws Throwable
jarloader.loadProcedures( jar );
}

public URL createJarFor( Class<?> ... targets ) throws IOException
@Test
public void shouldLogHelpfullyWhenPluginJarIsCorrupt() throws Exception
{
// given
URL theJar = createJarFor( ClassWithOneProcedure.class, ClassWithAnotherProcedure.class, ClassWithNoProcedureAtAll.class );
corruptJar( theJar );
AssertableLogProvider logProvider = new AssertableLogProvider( true );

ProcedureJarLoader jarloader = new ProcedureJarLoader(
new ReflectiveProcedureCompiler( new TypeMappers(), new ComponentRegistry(), NullLog.getInstance(), ProcedureAllowedConfig.DEFAULT ),
logProvider.getLog( ProcedureJarLoader.class ) );

// when
try
{
jarloader.loadProceduresFromDir( new File( theJar.getFile() ).getParentFile() );
fail("Should have logged and thrown exception.");
}
catch ( ZipException expected )
{
// then
logProvider.assertContainsLogCallContaining( String.format( "Plugin jar file: %s corrupted. Please reinstall.", theJar.getFile() ) );
}
}

private void corruptJar( URL jar ) throws IOException, URISyntaxException
{
long fileLength = new File( jar.getFile() ).length();
byte[] bytes = Files.readAllBytes( Paths.get( jar.toURI() ) );
for ( long i = fileLength/2; i < fileLength; i++ )
{
bytes[(int)i]= 0;
}

Files.write( Paths.get( jar.getPath() ), bytes );
}

private URL createJarFor( Class<?> ... targets ) throws IOException
{
return new JarBuilder().createJarFor( tmpdir.newFile( new Random().nextInt() + ".jar" ), targets );
}

public static class Output
{
public long someNumber = 1337;
public long someNumber = 1337; // Public because needed by a mapper

public Output()
{
Expand Down

0 comments on commit 3c92efe

Please sign in to comment.