/**
* Copyright 2010 JBoss Inc
*
* 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 org.drools.agent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.drools.core.util.DroolsStreamUtils;
import org.drools.definitions.impl.KnowledgePackageImp;
import org.drools.rule.Package;
/**
* This will monitor a file to a binary package.
*
* @author Michael Neale
*
*/
public class FileScanner extends PackageProvider {
File[] files;
Map lastUpdated = new HashMap();
Map<String, String> pathToPackage = null;
/**
* This sets the list of files to be monitored. This takes a list of paths
* and files (not directories).
*/
void configure(Properties config) {
List paths = RuleAgent.list( config.getProperty( RuleAgent.FILES ) );
files = new File[paths.size()];
for ( int i = 0; i < paths.size(); i++ ) {
File file = new File( (String) paths.get( i ) );
if ( !file.exists() ) {
throw new IllegalArgumentException( "The file " + file.getName() + " does not exist." );
}
files[i] = file;
}
}
/**
* An alternative way to configure.
*/
void setFiles(File[] files) {
this.files = files;
}
/**
* Perform the scan. If there was an error reading the packages, this will
* not fail, it will just do nothing (as there may be a temporary IO issue).
*/
PackageChangeInfo loadPackageChanges() {
PackageChangeInfo changes = getChangeSet();
return changes;
}
/**
* Calculate a change set, based on last updated times. (keep a map of
* files).
*/
private PackageChangeInfo getChangeSet() {
PackageChangeInfo info = new PackageChangeInfo();
if ( this.files == null ) return info;
if ( pathToPackage == null ) pathToPackage = new HashMap<String, String>();
for ( int i = 0; i < files.length; i++ ) {
File f = files[i];
if ( !f.exists() ) {
String name = pathToPackage.get( f.getPath() );
if ( name != null ) {
info.addRemovedPackage( name );
}
} else if ( hasChanged( f.getPath(),
this.lastUpdated,
f.lastModified() ) ) {
Package p = readPackage( f );
if ( p != null ) {
info.addPackage( p );
pathToPackage.put( f.getPath(),
p.getName() );
}
}
}
return info;
}
/**
* If an exception occurs, it is noted, but ignored. Especially IO, as
* generally they are temporary.
*/
private Package readPackage(File pkgFile) {
String name = pkgFile.getName();
if ( !(name.endsWith( ".pkg" ) || name.endsWith( ".drl" ) || name.endsWith( ".xls" )) ) {
return null;
}
// use reflection to load if its DRL, the provider lives in drools
// compiler.
if ( pkgFile.getName().endsWith( ".drl" ) ) {
try {
FileLoader fl = (FileLoader) Class.forName( "org.drools.compiler.SourcePackageProvider" ).newInstance();
return fl.loadPackage( pkgFile );
} catch ( Exception e ) {
this.listener.exception( e );
return null;
}
// use reflection to load if its XLS, the provider lives in drools
// decision tables.
} else if ( pkgFile.getName().endsWith( ".xls" ) ) {
try {
FileLoader fl = (FileLoader) Class.forName( "org.drools.decisiontable.SourcePackageProvider" ).newInstance();
return fl.loadPackage( pkgFile );
} catch ( Exception e ) {
this.listener.exception( e );
return null;
}
} else {
Object o = null;
try {
FileInputStream fis = new FileInputStream( pkgFile );
o = DroolsStreamUtils.streamIn( fis );
fis.close();
} catch ( FileNotFoundException e ) {
this.listener.exception( e );
this.listener.warning( "Was unable to find the file " + pkgFile.getPath() );
} catch ( IOException e ) {
this.listener.exception( e );
} catch ( ClassNotFoundException e ) {
this.listener.exception( e );
this.listener.warning( "Was unable to load a class when loading a package. Perhaps it is missing from this application." );
}
if ( o instanceof KnowledgePackageImp ) {
return ((KnowledgePackageImp) o).pkg;
} else {
return (Package) o;
}
}
}
boolean hasChanged(String path,
Map updates,
long fileLastModified) {
if ( !updates.containsKey( path ) ) {
updates.put( path,
new Long( fileLastModified ) );
return true;
} else {
Long last = (Long) updates.get( path );
if ( last.longValue() < fileLastModified ) {
updates.put( path,
new Long( fileLastModified ) );
return true;
} else {
return false;
}
}
}
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append( "FileScanner scanning: " );
for ( int i = 0; i < files.length; i++ ) {
File f = files[i];
buf.append( f.getPath() + " " );
}
return buf.toString();
}
}