[jboss-svn-commits] JBL Code SVN: r28588 - in labs/jbossrules/trunk: drools-compiler/src/test/java/org/drools/agent and 1 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Wed Jul 29 22:40:58 EDT 2009
Author: michael.neale at jboss.com
Date: 2009-07-29 22:40:58 -0400 (Wed, 29 Jul 2009)
New Revision: 28588
Added:
labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/UrlResourceTest.java
Modified:
labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgentFactory.java
labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentTest.java
labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/UrlResource.java
Log:
JBRULES-2219 UrlResource caching
Modified: labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgentFactory.java
===================================================================
--- labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgentFactory.java 2009-07-30 01:33:01 UTC (rev 28587)
+++ labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgentFactory.java 2009-07-30 02:40:58 UTC (rev 28588)
@@ -74,6 +74,17 @@
* ResourceFactory.getResourceChangeNotifierService().start();
* ResourceFactory.getResourceChangeScannerService().start();
* </pre>
+ *
+ * <p>
+ * For resources that are "polled" from a remote source (via http or similar) - sometimes you may want a local file based cache,
+ * in case the remote service is not available for whatever reason.
+ * To enable this:
+ * Set the system property: "drools.resource.urlcache" to a directory which can be written to and read from
+ * as a cache - so remote resources will be cached with last known good copies. This will allow the service to be restarted
+ * even if the remote source is not available.
+ * For example -Ddrools.resource.urlcache=/home/rulecaches
+ *
+ * </p>
*
* @see org.drools.agent.KnowledgeAgent
* @see org.drools.agent.KnowledgeAgentConfiguration
Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentTest.java 2009-07-30 01:33:01 UTC (rev 28587)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentTest.java 2009-07-30 02:40:58 UTC (rev 28588)
@@ -33,6 +33,7 @@
import org.drools.io.ResourceFactory;
import org.drools.io.impl.ResourceChangeNotifierImpl;
import org.drools.io.impl.ResourceChangeScannerImpl;
+import org.drools.io.impl.UrlResource;
import org.drools.runtime.StatefulKnowledgeSession;
import org.drools.runtime.StatelessKnowledgeSession;
import org.drools.runtime.pipeline.Action;
@@ -80,6 +81,10 @@
}
public void testModifyFileUrl() throws Exception {
+
+
+ UrlResource.CACHE_DIR = new File(".");
+
String rule1 = "";
rule1 += "package org.drools.test\n";
rule1 += "global java.util.List list\n";
@@ -184,7 +189,24 @@
assertTrue( list.contains( "rule3" ) );
assertTrue( list.contains( "rule2" ) );
- kagent.monitorResourceChangeEvents( false );
+ kagent.monitorResourceChangeEvents( false );
+
+ server.stop();
+
+
+ //now try it with the server stopped, so cache has to be used...
+ kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent",
+ kbase,
+ aconf );
+ kagent.monitorResourceChangeEvents(true);
+ assertEquals("test agent", kagent.getName());
+
+
+ //hmmm...
+ kagent.applyChangeSet( ResourceFactory.newFileResource(fxml) );
+
+ ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
+ assertNotNull(ksession);
}
public void testModifyFileUrlWithStateless() throws Exception {
@@ -286,7 +308,12 @@
assertTrue( list.contains( "rule3" ) );
assertTrue( list.contains( "rule2" ) );
- kagent.monitorResourceChangeEvents( false );
+
+
+ kagent.monitorResourceChangeEvents( false );
+
+
+
}
public void testModifyPackageUrl() throws Exception {
Added: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/UrlResourceTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/UrlResourceTest.java (rev 0)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/UrlResourceTest.java 2009-07-30 02:40:58 UTC (rev 28588)
@@ -0,0 +1,162 @@
+package org.drools.agent;
+
+import junit.framework.TestCase;
+import org.drools.io.impl.UrlResource;
+import org.drools.io.impl.ResourceChangeScannerImpl;
+import org.drools.io.impl.ResourceChangeNotifierImpl;
+import org.drools.io.ResourceFactory;
+import org.drools.util.FileManager;
+import org.drools.util.StringUtils;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.handler.ResourceHandler;
+
+import java.io.File;
+import java.io.Writer;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URL;
+
+/**
+ * @author Michael Neale
+ */
+public class UrlResourceTest extends TestCase {
+ private FileManager fileManager;
+ private Server server;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ fileManager = new FileManager();
+ fileManager.setUp();
+ ((ResourceChangeScannerImpl) ResourceFactory.getResourceChangeScannerService()).reset();
+ ResourceFactory.getResourceChangeNotifierService().start();
+ ResourceFactory.getResourceChangeScannerService().start();
+
+ this.server = new Server( 9000 );
+ ResourceHandler resourceHandler = new ResourceHandler();
+ resourceHandler.setResourceBase( fileManager.getRootDirectory().getPath() );
+ System.out.println("root : " + fileManager.getRootDirectory().getPath() );
+
+ server.setHandler( resourceHandler );
+
+ server.start();
+ }
+
+ protected void tearDown() throws Exception {
+ fileManager.tearDown();
+ ResourceFactory.getResourceChangeNotifierService().stop();
+ ResourceFactory.getResourceChangeScannerService().stop();
+ ((ResourceChangeNotifierImpl) ResourceFactory.getResourceChangeNotifierService()).reset();
+ ((ResourceChangeScannerImpl) ResourceFactory.getResourceChangeScannerService()).reset();
+
+ server.stop();
+ }
+
+
+ public void testWithCache() throws Exception {
+ URL url = new URL("http://localhost:9000/rule1.drl");
+ UrlResource ur = new UrlResource(url);
+ UrlResource.CACHE_DIR = new File(".");
+
+ File f1 = fileManager.newFile( "rule1.drl" );
+ System.err.println("target file: " + f1.getAbsolutePath());
+ Writer output = new BufferedWriter( new FileWriter( f1 ) );
+ output.write( "Some data" );
+ output.close();
+
+ long lm = ur.getLastModified();
+ assertTrue(lm > 0);
+
+ InputStream ins = ur.getInputStream();
+ assertNotNull(ins);
+
+ server.stop();
+
+ assertNotNull(ur.getInputStream());
+
+ assertTrue(ur.getLastModified() > 0);
+
+ assertTrue(ur.getInputStream() instanceof FileInputStream);
+
+
+ //now write some more stuff
+ Thread.sleep(1000);
+ f1.delete();
+ output = new BufferedWriter( new FileWriter( f1 ) );
+ output.write( "More data..." );
+ output.close();
+
+ server.start();
+ assertNotNull(ur.getInputStream());
+ assertFalse(ur.getInputStream() instanceof FileInputStream);
+ long lm_ = ur.getLastModified();
+ System.err.println("lm_ : " + lm_ + " lm : " + lm );
+
+ assertTrue(lm_ > lm);
+
+ InputStream in_= ur.getInputStream();
+ BufferedReader rdr = new BufferedReader(new InputStreamReader(in_));
+ String line = rdr.readLine();
+ assertEquals("More data...", line);
+
+ server.stop();
+
+ Thread.sleep(1000);
+ f1.delete();
+ output = new BufferedWriter( new FileWriter( f1 ) );
+ output.write( "Finally.." );
+ output.close();
+
+ //now it should be cached, so using old copy still... (server has stopped serving it up)
+ ur = new UrlResource(url);
+ in_= ur.getInputStream();
+ rdr = new BufferedReader(new InputStreamReader(in_));
+ line = rdr.readLine();
+ assertEquals("More data...", line);
+
+ Thread.sleep(1000);
+ server.start();
+
+ ur = new UrlResource(url);
+ //server is started, so should have latest...
+ in_= ur.getInputStream();
+ rdr = new BufferedReader(new InputStreamReader(in_));
+ line = rdr.readLine();
+ assertEquals("Finally..", line);
+
+
+
+
+ }
+
+ public void testWithoutCache() throws Exception {
+ UrlResource ur = new UrlResource(new URL("http://localhost:9000/rule1.drl"));
+ UrlResource.CACHE_DIR = null;
+
+ File f1 = fileManager.newFile( "rule1.drl" );
+ System.err.println("target file: " + f1.getAbsolutePath());
+ Writer output = new BufferedWriter( new FileWriter( f1 ) );
+ output.write( "Some data" );
+ output.close();
+
+ long lm = ur.getLastModified();
+ assertTrue(lm > 0);
+
+ InputStream ins = ur.getInputStream();
+ assertNotNull(ins);
+
+ server.stop();
+ assertEquals(0, ur.getLastModified());
+
+
+
+
+
+ }
+
+
+
+}
Property changes on: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/UrlResourceTest.java
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/UrlResource.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/UrlResource.java 2009-07-30 01:33:01 UTC (rev 28587)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/UrlResource.java 2009-07-30 02:40:58 UTC (rev 28588)
@@ -8,10 +8,16 @@
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileInputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
+import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -25,13 +31,23 @@
/**
* Borrowed gratuitously from Spring under ASL2.0.
*
+ * Added in local file cache ability for http and https urls.
+ *
+ * Set the system property: "drools.resource.urlcache" to a directory which can be written to and read from
+ * as a cache - so remote resources will be cached with last known good copies.
*/
public class UrlResource extends BaseResource
implements
InternalResource,
Externalizable {
+
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+ public static File CACHE_DIR = getCacheDir();
+
private URL url;
private long lastRead = -1;
+ private static final String DROOLS_RESOURCE_URLCACHE = "drools.resource.urlcache";
public UrlResource() {
@@ -70,7 +86,69 @@
* @see java.net.URLConnection#getInputStream()
*/
public InputStream getInputStream() throws IOException {
- this.lastRead = getLastModified();
+ try {
+ long lastMod = grabLastMod();
+ if (lastMod == 0) {
+ //we will try the cache...
+ if (cacheFileExists()) return fromCache();
+ }
+ if (lastMod > 0 && lastMod > lastRead) {
+ if (CACHE_DIR != null && url.getProtocol().equals("http") || url.getProtocol().equals("https")) {
+ //lets grab a copy and cache it in case we need it in future...
+ cacheStream();
+ }
+ }
+ this.lastRead = lastMod;
+ return grabStream();
+ } catch (IOException e) {
+ if (cacheFileExists()) {
+ return fromCache();
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ private boolean cacheFileExists() {
+ return CACHE_DIR != null && getCacheFile().exists();
+ }
+
+ private InputStream fromCache() throws FileNotFoundException, UnsupportedEncodingException {
+ File fi = getCacheFile();
+ return new FileInputStream(fi);
+ }
+
+ private File getCacheFile() {
+ try {
+ return new File(CACHE_DIR, URLEncoder.encode(this.url.toString(), "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Save a copy in the local cache - in case remote source is not available in future.
+ */
+ private void cacheStream() {
+ try {
+ File fi = getCacheFile();
+ if (fi.exists()) fi.delete();
+ FileOutputStream fout = new FileOutputStream(fi);
+ InputStream in = grabStream();
+ byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+ int n;
+ while (-1 != (n = in.read(buffer))) {
+ fout.write(buffer, 0, n);
+ }
+ fout.flush();
+ fout.close();
+ in.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private InputStream grabStream() throws IOException {
URLConnection con = this.url.openConnection();
con.setUseCaches( false );
return con.getInputStream();
@@ -85,7 +163,6 @@
* @param originalUrl the original URL
* @param originalPath the original URL path
* @return the cleaned URL
- * @see org.springframework.util.StringUtils#cleanPath
*/
private URL getCleanedUrl(URL originalUrl,
String originalPath) {
@@ -116,30 +193,46 @@
public long getLastModified() {
try {
- // use File, as http rounds milliseconds on some machines, this fine level of granularity is only really an issue for testing
- // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4504473
- if ( "file".equals( url.getProtocol() ) ) {
- File file = getFile();
- return file.lastModified();
+ long lm = grabLastMod();
+ //try the cache.
+ if (lm == 0 && cacheFileExists()) {
+ //OK we will return it from the local cached copy, as remote one isn't available..
+ return getCacheFile().lastModified();
+ }
+ return lm;
+ } catch ( IOException e ) {
+ //try the cache...
+ if (cacheFileExists()) {
+ //OK we will return it from the local cached copy, as remote one isn't available..
+ return getCacheFile().lastModified();
} else {
- URLConnection conn = getURL().openConnection();
- if ( conn instanceof HttpURLConnection ) {
- ((HttpURLConnection) conn).setRequestMethod( "HEAD" );
- }
- long date = conn.getLastModified();
- if (date == 0) {
- try {
- date = Long.parseLong(conn.getHeaderField("lastModified"));
- } catch (Exception e) { /* well, we tried ... */ }
- }
- return date;
+ throw new RuntimeException( "Unable to get LastMofified for ClasspathResource",
+ e );
}
- } catch ( IOException e ) {
- throw new RuntimeException( "Unable to get LastMofified for ClasspathResource",
- e );
}
}
+ private long grabLastMod() throws IOException {
+ // use File, as http rounds milliseconds on some machines, this fine level of granularity is only really an issue for testing
+ // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4504473
+ if ( "file".equals( url.getProtocol() ) ) {
+ File file = getFile();
+ return file.lastModified();
+ } else {
+ URLConnection conn = getURL().openConnection();
+ if ( conn instanceof HttpURLConnection) {
+ ((HttpURLConnection) conn).setRequestMethod( "HEAD" );
+ }
+ long date = conn.getLastModified();
+ if (date == 0) {
+ try {
+ date = Long.parseLong(conn.getHeaderField("lastModified"));
+ } catch (Exception e) { /* well, we tried ... */ }
+ }
+ return date;
+ }
+ }
+
public long getLastRead() {
return this.lastRead;
}
@@ -203,4 +296,12 @@
return "[UrlResource path='" + this.url.toString() + "']";
}
+ private static File getCacheDir() {
+ String root = System.getProperty(DROOLS_RESOURCE_URLCACHE, "NONE");
+ if (root.equals("NONE")) {
+ return null;
+ } else {
+ return new File(root);
+ }
+ }
}
More information about the jboss-svn-commits
mailing list