/*
* Copyright (c) 2013-2014 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.werval.spi.dev;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import io.werval.api.exceptions.WervalException;
/**
* Adapter for DevShellSPI that listen to changes but has NOOP rebuild methods.
* <p>
* Extend and override {@link #doRebuild()} method to your will.
* <p>
* Note that this is the werval HttpServer responsibility to trigger rebuilds.
*/
public class DevShellSPIAdapter
implements DevShellSPI
{
private final URL[] applicationSources;
private final URL[] applicationClassPath;
private final URL[] runtimeClassPath;
private boolean sourceChanged;
protected DevShellSPIAdapter(
URL[] applicationSources,
URL[] applicationClassPath, URL[] runtimeClassPath,
Set<File> toWatch, SourceWatcher watcher,
boolean initialSourceChanged
)
{
this.applicationSources = Arrays.copyOf( applicationSources, applicationSources.length );
this.applicationClassPath = Arrays.copyOf( applicationClassPath, applicationClassPath.length );
this.runtimeClassPath = Arrays.copyOf( runtimeClassPath, runtimeClassPath.length );
// QUID Unwatch sources on DevShell passivation?
this.sourceChanged = initialSourceChanged;
watcher.watch(
toWatch,
new SourceChangeListener()
{
@Override
public void onChange()
{
System.out.println( "Source changed!" );
sourceChanged = true;
}
}
);
}
@Override
@SuppressWarnings( "ReturnOfCollectionOrArrayField" )
public final URL[] applicationClassPath()
{
return applicationClassPath;
}
@Override
@SuppressWarnings( "ReturnOfCollectionOrArrayField" )
public final URL[] runtimeClassPath()
{
return runtimeClassPath;
}
@Override
public String sourceURL( String packageName, final String fileName, int lineNumber )
{
final String packagePath = packageName.replaceAll( "\\.", "\\/" );
for( URL path : applicationSources )
{
try
{
File root = new File( path.toURI() );
if( root.isDirectory() )
{
final List<File> found = new ArrayList<>( 1 );
Files.walkFileTree(
root.toPath(),
new SimpleFileVisitor<Path>()
{
@Override
public FileVisitResult visitFile( Path path, BasicFileAttributes attrs )
throws IOException
{
File file = path.toFile();
if( fileName.equals( file.getName() ) && path.getParent().endsWith( packagePath ) )
{
found.add( file );
return FileVisitResult.TERMINATE;
}
return FileVisitResult.CONTINUE;
}
}
);
if( !found.isEmpty() )
{
return "file://" + found.get( 0 ).getAbsolutePath() + "#L" + lineNumber;
}
}
}
catch( URISyntaxException | IOException ex )
{
throw new WervalException( ex.getMessage(), ex );
}
}
return null;
}
@Override
public final boolean isSourceChanged()
{
return sourceChanged;
}
@Override
public final synchronized void rebuild()
throws DevShellRebuildException
{
if( sourceChanged )
{
doRebuild();
sourceChanged = false;
}
}
@Override
public final void stop()
{
doStop();
}
/**
* No operation.
*
* @throws DevShellRebuildException if rebuilding fails
*
* @see DevShellSPI#rebuild()
*/
protected void doRebuild()
throws DevShellRebuildException
{
// NOOP
}
/**
* No operation.
*
* @see DevShellSPI#stop()
*/
protected void doStop()
{
// NOOP
}
}