/**
* Copyright (c) 2008-2011 Sonatype, Inc.
* All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions.
*
* This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General
* Public License Version 3 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License Version 3
* for more details.
*
* You should have received a copy of the GNU Affero General Public License Version 3 along with this program. If not, see
* http://www.gnu.org/licenses.
*
* Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of
* Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation.
* All other trademarks are the property of their respective owners.
*/
package com.sonatype.nexus.plugin.groovyconsole;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.commons.vfs.FileChangeEvent;
import org.apache.commons.vfs.FileContent;
import org.apache.commons.vfs.FileListener;
import org.apache.commons.vfs.FileName;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSelectInfo;
import org.apache.commons.vfs.FileSelector;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileSystemManager;
import org.apache.commons.vfs.VFS;
import org.apache.commons.vfs.impl.DefaultFileMonitor;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.codehaus.plexus.util.FileUtils;
import org.sonatype.nexus.configuration.application.ApplicationConfiguration;
import org.sonatype.plexus.appevents.Event;
@Component( role = ScriptStorage.class )
public class DefaultScriptStorage
extends AbstractLogEnabled
implements ScriptStorage, Initializable, Disposable, FileListener
{
@Requirement
private ApplicationConfiguration applicationConfiguration;
private static final String GROOVY = "groovy";
private static final String DOT_GROOVY = "." + GROOVY;
private DefaultFileMonitor fileMonitor;
private Map<String, String> scripts;
private File scriptDir;
public void dispose()
{
fileMonitor.stop();
fileMonitor = null;
scripts.clear();
scripts = null;
scriptDir = null;
}
public void fileChanged( FileChangeEvent e )
throws Exception
{
if ( !isScriptFile( e.getFile() ) )
{
return;
}
updateScript( e.getFile() );
}
public void fileCreated( FileChangeEvent e )
throws Exception
{
if ( !isScriptFile( e.getFile() ) )
{
return;
}
updateScript( e.getFile() );
}
public void fileDeleted( FileChangeEvent e )
throws Exception
{
if ( !isScriptFile( e.getFile() ) )
{
return;
}
synchronized ( scripts )
{
scripts.remove( getName( e.getFile().getName() ) );
}
}
public String getScript( Class<? extends Event<?>> eventClass )
{
synchronized ( scripts )
{
return scripts.get( eventClass.getName() );
}
}
public void initialize()
throws InitializationException
{
scripts = new LinkedHashMap<String, String>();
FileObject listendir;
try
{
FileSystemManager fsManager = VFS.getManager();
scriptDir = applicationConfiguration.getWorkingDirectory( "scripts" );
if ( !scriptDir.exists() )
{
scriptDir.mkdirs();
try
{
new File( scriptDir, "place your .groovy files here.txt" ).createNewFile();
}
catch ( IOException e )
{
throw new InitializationException( e.getMessage(), e );
}
}
listendir = fsManager.resolveFile( scriptDir.getAbsolutePath() );
}
catch ( FileSystemException e )
{
throw new InitializationException( e.getMessage(), e );
}
FileSelector selector = new FileSelector()
{
public boolean traverseDescendents( FileSelectInfo arg0 )
throws Exception
{
return true;
}
public boolean includeFile( FileSelectInfo arg0 )
throws Exception
{
return isScriptFile( arg0.getFile() );
}
};
try
{
FileObject[] availableScripts = listendir.findFiles( selector );
for ( FileObject fileObject : availableScripts )
{
updateScript( fileObject );
}
}
catch ( FileSystemException e )
{
getLogger().warn( "Unable to perform initial directory scan.", e );
}
DefaultFileMonitor fm = new DefaultFileMonitor( this );
fm.setRecursive( true );
fm.addFile( listendir );
fm.start();
this.fileMonitor = fm;
}
private boolean isScriptFile( FileObject file )
{
FileName name = file.getName();
if ( name.getBaseName().endsWith( DOT_GROOVY ) )
{
return true;
}
return false;
}
private void updateScript( FileObject file )
{
FileName name = file.getName();
getLogger().info( "New script file found: " + name );
String script;
try
{
FileContent content = file.getContent();
script = IOUtils.toString( content.getInputStream() );
content.close();
}
catch ( IOException e )
{
getLogger().warn( "Unable to read script file: " + name, e );
return;
}
synchronized ( scripts )
{
scripts.put( getName( name ), script );
}
}
private String getName( FileName name )
{
String baseName = name.getBaseName();
baseName = baseName.substring( 0, baseName.length() - DOT_GROOVY.length() );
return baseName;
}
public Map<String, String> getScripts()
{
return Collections.unmodifiableMap( this.scripts );
}
public void store( String name, String script )
throws IOException
{
if ( !name.endsWith( DOT_GROOVY ) )
{
name = name + DOT_GROOVY;
}
File output = new File( scriptDir, name );
FileUtils.fileWrite( output.getAbsolutePath(), script );
synchronized ( scripts )
{
scripts.put( name, script );
}
}
}