Author: kwright
Date: Sun Sep 14 21:21:45 2014
New Revision: 1624906

URL: http://svn.apache.org/r1624906
Log:
Upgrade RSS connector.  Part of CONNECTORS-977

Modified:
    
manifoldcf/trunk/connectors/rss/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/rss/RSSConnector.java

Modified: 
manifoldcf/trunk/connectors/rss/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/rss/RSSConnector.java
URL: 
http://svn.apache.org/viewvc/manifoldcf/trunk/connectors/rss/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/rss/RSSConnector.java?rev=1624906&r1=1624905&r2=1624906&view=diff
==============================================================================
--- 
manifoldcf/trunk/connectors/rss/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/rss/RSSConnector.java
 (original)
+++ 
manifoldcf/trunk/connectors/rss/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/rss/RSSConnector.java
 Sun Sep 14 21:21:45 2014
@@ -702,27 +702,22 @@ public class RSSConnector extends org.ap
   }
 
 
-
-  /** Get document versions given an array of document identifiers.
-  * This method is called for EVERY document that is considered. It is
-  * therefore important to perform as little work as possible here.
-  *@param documentIdentifiers is the array of local document identifiers, as 
understood by this connector.
-  *@param oldVersions is the corresponding array of version strings that have 
been saved for the document identifiers.
-  *   A null value indicates that this is a first-time fetch, while an empty 
string indicates that the previous document
-  *   had an empty version string.
-  *@param activities is the interface this method should use to perform 
whatever framework actions are desired.
-  *@param spec is the current document specification for the current job.  If 
there is a dependency on this
-  * specification, then the version string should include the pertinent data, 
so that reingestion will occur
-  * when the specification changes.  This is primarily useful for metadata.
-  *@param jobType is an integer describing how the job is being run, whether 
continuous or once-only.
+  /** Process a set of documents.
+  * This is the method that should cause each document to be fetched, 
processed, and the results either added
+  * to the queue of documents for the current job, and/or entered into the 
incremental ingestion manager.
+  * The document specification allows this class to filter what is done based 
on the job.
+  * The connector will be connected before this method can be called.
+  *@param documentIdentifiers is the set of document identifiers to process.
+  *@param statuses are the currently-stored document versions for each 
document in the set of document identifiers
+  * passed in above.
+  *@param activities is the interface this method should use to queue up new 
document references
+  * and ingest documents.
+  *@param jobMode is an integer describing how the job is being run, whether 
continuous or once-only.
   *@param usesDefaultAuthority will be true only if the authority in use for 
these documents is the default one.
-  *@return the corresponding version strings, with null in the places where 
the document no longer exists.
-  * Empty version strings indicate that there is no versioning ability for the 
corresponding document, and the document
-  * will always be processed.
   */
   @Override
-  public String[] getDocumentVersions(String[] documentIdentifiers, String[] 
oldVersions, IVersionActivity activities,
-    DocumentSpecification spec, int jobType, boolean usesDefaultAuthority)
+  public void processDocuments(String[] documentIdentifiers, IExistingVersions 
statuses, Specification spec,
+    IProcessActivity activities, int jobMode, boolean usesDefaultAuthority)
     throws ManifoldCFException, ServiceInterruption
   {
     getSession();
@@ -732,6 +727,8 @@ public class RSSConnector extends org.ap
     // thought to set up properly.
     int connectionLimit = 200;
 
+    String[] fixedList = new String[2];
+
     if (Logging.connectors.isDebugEnabled())
       Logging.connectors.debug("RSS: In getDocumentVersions for 
"+Integer.toString(documentIdentifiers.length)+" documents");
 
@@ -757,183 +754,185 @@ public class RSSConnector extends org.ap
 
     int feedTimeout = f.getFeedTimeoutValue();
 
-    // A preliminary fetch must be done in either case, because otherwise we 
cannot detect a deletion.
-    // But, since we don't want to fetch twice, write these urls to temporary 
files.  The
-    // files will be cleaned up as soon as possible.
-
-    String[] rval = new String[documentIdentifiers.length];
-
-    // HttpClient client = new HttpClient(httpConMan.getManager());
-
     // The document specification has already been used to trim out documents 
that are not
     // allowed from appearing in the queue.  So, even that has already been 
done.
-    int i = 0;
-    while (i < documentIdentifiers.length)
+    for (String documentIdentifier : documentIdentifiers)
     {
       // If it is in this list, we presume that it has been vetted against the 
map etc., so we don't do that again.  We just fetch it.
       // And, if the content type is xml, we calculate the version as if it is 
a feed rather than a document.
 
       // Get the url
-      String urlValue = documentIdentifiers[i];
+      String urlValue = documentIdentifier;
 
       if (Logging.connectors.isDebugEnabled())
         Logging.connectors.debug("RSS: Getting version string for 
'"+urlValue+"'");
 
-      // If there's a carrydown "data" value for this url, we use that value 
rather than actually fetching the document.  This also means we don't need to
-      // do a robots check, because we aren't actually crawling anything.  So, 
ALWAYS do this first...
-      CharacterInput[] dechromedData = 
activities.retrieveParentDataAsFiles(urlValue,"data");
+      String versionString;
+      String ingestURL = null;
+      String[] pubDates = null;
+      String[] sources = null;
+      String[] titles = null;
+      String[] authorNames = null;
+      String[] authorEmails = null;
+      String[] categories = null;
+      String[] descriptions = null;
+                  
       try
       {
-        if (dechromedData.length > 0)
+        // If there's a carrydown "data" value for this url, we use that value 
rather than actually fetching the document.  This also means we don't need to
+        // do a robots check, because we aren't actually crawling anything.  
So, ALWAYS do this first...
+        CharacterInput[] dechromedData = 
activities.retrieveParentDataAsFiles(urlValue,"data");
+        try
         {
-          // Data already available.  The fetch cycle can be entirely avoided, 
as can the robots check.
-          String ingestURL = f.mapDocumentURL(urlValue);
-          if (ingestURL != null)
+          if (dechromedData.length > 0)
           {
-            // Open up an input stream corresponding to the carrydown data.  
The stream will be encoded as utf-8.
-            try
+            // Data already available.  The fetch cycle can be entirely 
avoided, as can the robots check.
+            ingestURL = f.mapDocumentURL(urlValue);
+            if (ingestURL != null)
             {
-              InputStream is = dechromedData[0].getUtf8Stream();
+              // Open up an input stream corresponding to the carrydown data.  
The stream will be encoded as utf-8.
               try
               {
-                StringBuilder sb = new StringBuilder();
-                long checkSum = 
cache.addData(activities,urlValue,"text/html",is);
-                // Grab what we need from the passed-down data for the 
document.  These will all become part
-                // of the version string.
-                String[] pubDates = 
activities.retrieveParentData(urlValue,"pubdate");
-                String[] sources = 
activities.retrieveParentData(urlValue,"source");
-                String[] titles = 
activities.retrieveParentData(urlValue,"title");
-                String[] authorNames = 
activities.retrieveParentData(urlValue,"authorname");
-                String[] authorEmails = 
activities.retrieveParentData(urlValue,"authoremail");
-                String[] categories = 
activities.retrieveParentData(urlValue,"category");
-                String[] descriptions = 
activities.retrieveParentData(urlValue,"description");
-                java.util.Arrays.sort(pubDates);
-                java.util.Arrays.sort(sources);
-                java.util.Arrays.sort(titles);
-                java.util.Arrays.sort(authorNames);
-                java.util.Arrays.sort(authorEmails);
-                java.util.Arrays.sort(categories);
-                java.util.Arrays.sort(descriptions);
-
-                if (sources.length == 0)
+                InputStream is = dechromedData[0].getUtf8Stream();
+                try
                 {
-                  if (Logging.connectors.isDebugEnabled())
-                    Logging.connectors.debug("RSS: Warning; URL 
'"+ingestURL+"' doesn't seem to have any RSS feed source!");
-                }
+                  StringBuilder sb = new StringBuilder();
+                  long checkSum = 
cache.addData(activities,urlValue,"text/html",is);
+                  // Grab what we need from the passed-down data for the 
document.  These will all become part
+                  // of the version string.
+                  pubDates = activities.retrieveParentData(urlValue,"pubdate");
+                  sources = activities.retrieveParentData(urlValue,"source");
+                  titles = activities.retrieveParentData(urlValue,"title");
+                  authorNames = 
activities.retrieveParentData(urlValue,"authorname");
+                  authorEmails = 
activities.retrieveParentData(urlValue,"authoremail");
+                  categories = 
activities.retrieveParentData(urlValue,"category");
+                  descriptions = 
activities.retrieveParentData(urlValue,"description");
+                  java.util.Arrays.sort(pubDates);
+                  java.util.Arrays.sort(sources);
+                  java.util.Arrays.sort(titles);
+                  java.util.Arrays.sort(authorNames);
+                  java.util.Arrays.sort(authorEmails);
+                  java.util.Arrays.sort(categories);
+                  java.util.Arrays.sort(descriptions);
+
+                  if (sources.length == 0)
+                  {
+                    if (Logging.connectors.isDebugEnabled())
+                      Logging.connectors.debug("RSS: Warning; URL 
'"+ingestURL+"' doesn't seem to have any RSS feed source!");
+                  }
 
-                sb.append('+');
-                packList(sb,acls,'+');
-                if (acls.length > 0)
-                {
                   sb.append('+');
-                  pack(sb,defaultAuthorityDenyToken,'+');
-                }
-                else
-                  sb.append('-');
-                // The ingestion URL
-                pack(sb,ingestURL,'+');
-                // The pub dates
-                packList(sb,pubDates,'+');
-                // The titles
-                packList(sb,titles,'+');
-                // The sources
-                packList(sb,sources,'+');
-                // The categories
-                packList(sb,categories,'+');
-                // The descriptions
-                packList(sb,descriptions,'+');
-                // The author names
-                packList(sb,authorNames,'+');
-                // The author emails
-                packList(sb,authorEmails,'+');
+                  packList(sb,acls,'+');
+                  if (acls.length > 0)
+                  {
+                    sb.append('+');
+                    pack(sb,defaultAuthorityDenyToken,'+');
+                  }
+                  else
+                    sb.append('-');
+                  // The ingestion URL
+                  pack(sb,ingestURL,'+');
+                  // The pub dates
+                  packList(sb,pubDates,'+');
+                  // The titles
+                  packList(sb,titles,'+');
+                  // The sources
+                  packList(sb,sources,'+');
+                  // The categories
+                  packList(sb,categories,'+');
+                  // The descriptions
+                  packList(sb,descriptions,'+');
+                  // The author names
+                  packList(sb,authorNames,'+');
+                  // The author emails
+                  packList(sb,authorEmails,'+');
 
-                // Do the checksum part, which does not need to be parseable.
-                sb.append(new Long(checkSum).toString());
+                  // Do the checksum part, which does not need to be parseable.
+                  sb.append(new Long(checkSum).toString());
 
-                rval[i] = sb.toString();
+                  versionString = sb.toString();
+                }
+                finally
+                {
+                  is.close();
+                }
               }
-              finally
+              catch (java.net.SocketTimeoutException e)
               {
-                is.close();
+                throw new ManifoldCFException("IO exception reading data from 
string: "+e.getMessage(),e);
+              }
+              catch (InterruptedIOException e)
+              {
+                throw new ManifoldCFException("Interrupted: 
"+e.getMessage(),e,ManifoldCFException.INTERRUPTED);
+              }
+              catch (IOException e)
+              {
+                throw new ManifoldCFException("IO exception reading data from 
string: "+e.getMessage(),e);
               }
             }
-            catch (java.net.SocketTimeoutException e)
-            {
-              throw new ManifoldCFException("IO exception reading data from 
string: "+e.getMessage(),e);
-            }
-            catch (InterruptedIOException e)
-            {
-              throw new ManifoldCFException("Interrupted: 
"+e.getMessage(),e,ManifoldCFException.INTERRUPTED);
-            }
-            catch (IOException e)
+            else
             {
-              throw new ManifoldCFException("IO exception reading data from 
string: "+e.getMessage(),e);
+              // Document a seed or unmappable; just skip
+              if (Logging.connectors.isDebugEnabled())
+                Logging.connectors.debug("RSS: Skipping carry-down document 
'"+urlValue+"' because it is unmappable or is a seed.");
             }
           }
           else
           {
-            // Document a seed or unmappable; just skip
-            if (Logging.connectors.isDebugEnabled())
-              Logging.connectors.debug("RSS: Skipping carry-down document 
'"+urlValue+"' because it is unmappable or is a seed.");
-          }
-        }
-        else
-        {
-          // Get the old version string
-          String oldVersionString = oldVersions[i];
+            // Get the old version string
+            String oldVersionString = 
statuses.getIndexedVersionString(documentIdentifier);
 
-          // Unpack the old version as much as possible.
-          // We are interested in what the ETag and Last-Modified headers were 
last time.
-          String lastETagValue = null;
-          String lastModifiedValue = null;
-          // Note well: Non-continuous jobs cannot use etag because the rss 
document MUST be fetched each time for such jobs,
-          // or the documents it points at would get deleted.
-          //
-          // NOTE: I disabled this code because we really need the feed's TTL 
value in order to reschedule properly.  I can't get the
-          // TTL value without refetching the document - therefore ETag and 
Last-Modified cannot be used :-(
-          if (false && jobType == JOBMODE_CONTINUOUS && oldVersionString != 
null && oldVersionString.startsWith("-"))
-          {
-            // It's a feed, so the last etag and last-modified fields should 
be encoded in this version string.
-            StringBuilder lastETagBuffer = new StringBuilder();
-            int unpackPos = unpack(lastETagBuffer,oldVersionString,1,'+');
-            StringBuilder lastModifiedBuffer = new StringBuilder();
-            unpackPos = 
unpack(lastModifiedBuffer,oldVersionString,unpackPos,'+');
-            if (lastETagBuffer.length() > 0)
-              lastETagValue = lastETagBuffer.toString();
-            if (lastModifiedBuffer.length() > 0)
-              lastModifiedValue = lastModifiedBuffer.toString();
-          }
-
-          if (Logging.connectors.isDebugEnabled() && (lastETagValue != null || 
lastModifiedValue != null))
-            Logging.connectors.debug("RSS: Document '"+urlValue+"' was found 
to have a previous ETag value of 
'"+((lastETagValue==null)?"null":lastETagValue)+
-            "' and a previous Last-Modified value of 
'"+((lastModifiedValue==null)?"null":lastModifiedValue)+"'");
+            // Unpack the old version as much as possible.
+            // We are interested in what the ETag and Last-Modified headers 
were last time.
+            String lastETagValue = null;
+            String lastModifiedValue = null;
+            // Note well: Non-continuous jobs cannot use etag because the rss 
document MUST be fetched each time for such jobs,
+            // or the documents it points at would get deleted.
+            //
+            // NOTE: I disabled this code because we really need the feed's 
TTL value in order to reschedule properly.  I can't get the
+            // TTL value without refetching the document - therefore ETag and 
Last-Modified cannot be used :-(
+            if (false && jobMode == JOBMODE_CONTINUOUS && oldVersionString != 
null && oldVersionString.startsWith("-"))
+            {
+              // It's a feed, so the last etag and last-modified fields should 
be encoded in this version string.
+              StringBuilder lastETagBuffer = new StringBuilder();
+              int unpackPos = unpack(lastETagBuffer,oldVersionString,1,'+');
+              StringBuilder lastModifiedBuffer = new StringBuilder();
+              unpackPos = 
unpack(lastModifiedBuffer,oldVersionString,unpackPos,'+');
+              if (lastETagBuffer.length() > 0)
+                lastETagValue = lastETagBuffer.toString();
+              if (lastModifiedBuffer.length() > 0)
+                lastModifiedValue = lastModifiedBuffer.toString();
+            }
+
+            if (Logging.connectors.isDebugEnabled() && (lastETagValue != null 
|| lastModifiedValue != null))
+              Logging.connectors.debug("RSS: Document '"+urlValue+"' was found 
to have a previous ETag value of 
'"+((lastETagValue==null)?"null":lastETagValue)+
+              "' and a previous Last-Modified value of 
'"+((lastModifiedValue==null)?"null":lastModifiedValue)+"'");
 
-          // Robots check.  First, we need to separate the url into its 
components
-          try
-          {
-            URL url = new URL(urlValue);
-            String protocol = url.getProtocol();
-            int port = url.getPort();
-            String hostName = url.getHost();
-            String pathPart = url.getFile();
-
-            // Check with robots to see if it's allowed
-            if (robotsUsage >= ROBOTS_DATA && 
!robots.isFetchAllowed(currentContext,throttleGroupName,
-              protocol,port,hostName,url.getPath(),
-              userAgent,from,
-              proxyHost, proxyPort, proxyAuthDomain, proxyAuthUsername, 
proxyAuthPassword,
-              activities, connectionLimit))
-            {
-              activities.recordActivity(null,ACTIVITY_FETCH,
-                null,urlValue,Integer.toString(-2),"Robots exclusion",null);
-
-              if (Logging.connectors.isDebugEnabled())
-                Logging.connectors.debug("RSS: Skipping url '"+urlValue+"' 
because robots.txt says to");
-              rval[i] = null;
-            }
-            else
+            // Robots check.  First, we need to separate the url into its 
components
+            try
             {
+              URL url = new URL(urlValue);
+              String protocol = url.getProtocol();
+              int port = url.getPort();
+              String hostName = url.getHost();
+              String pathPart = url.getFile();
+
+              // Check with robots to see if it's allowed
+              if (robotsUsage >= ROBOTS_DATA && 
!robots.isFetchAllowed(currentContext,throttleGroupName,
+                protocol,port,hostName,url.getPath(),
+                userAgent,from,
+                proxyHost, proxyPort, proxyAuthDomain, proxyAuthUsername, 
proxyAuthPassword,
+                activities, connectionLimit))
+              {
+                activities.recordActivity(null,ACTIVITY_FETCH,
+                  null,urlValue,Integer.toString(-2),"Robots exclusion",null);
 
+                if (Logging.connectors.isDebugEnabled())
+                  Logging.connectors.debug("RSS: Skipping url '"+urlValue+"' 
because robots.txt says to");
+                activities.deleteDocument(documentIdentifier);
+                continue;
+              }
+              
               // Now, use the fetcher, and get the file.
               IThrottledConnection connection = 
fetcher.createConnection(currentContext,
                 throttleGroupName,
@@ -958,7 +957,7 @@ public class RSSConnector extends org.ap
                   switch (status)
                   {
                   case IThrottledConnection.STATUS_NOCHANGE:
-                    rval[i] = oldVersionString;
+                    versionString = oldVersionString;
                     break;
                   case IThrottledConnection.STATUS_OK:
                     try
@@ -987,7 +986,7 @@ public class RSSConnector extends org.ap
                         contentType.startsWith("application/rdf+xml") ||
                         contentType.startsWith("text/application") ||
                         contentType.startsWith("XML") ));
-                      String ingestURL = null;
+                      ingestURL = null;
                       if (!isXML)
                       {
                         // If the chromed content mode is set to "skip", and 
we got here, it means
@@ -996,7 +995,7 @@ public class RSSConnector extends org.ap
                         {
                           if (Logging.connectors.isDebugEnabled())
                             Logging.connectors.debug("RSS: Removing url 
'"+urlValue+"' because it no longer has dechromed content available");
-                          rval[i] = null;
+                          versionString = null;
                           break;
                         }
 
@@ -1007,7 +1006,7 @@ public class RSSConnector extends org.ap
                         {
                           if (Logging.connectors.isDebugEnabled())
                             Logging.connectors.debug("RSS: Removing url 
'"+urlValue+"' because it had the wrong content type: 
"+((contentType==null)?"null":"'"+contentType+"'"));
-                          rval[i] = null;
+                          versionString = null;
                           break;
                         }
 
@@ -1023,7 +1022,7 @@ public class RSSConnector extends org.ap
                           // Remove the feed from consideration, since it has 
left the list of seeds
                           if (Logging.connectors.isDebugEnabled())
                             Logging.connectors.debug("RSS: Removing feed url 
'"+urlValue+"' because it is not a seed.");
-                          rval[i] = null;
+                          versionString = null;
                           break;
                         }
                       }
@@ -1039,13 +1038,13 @@ public class RSSConnector extends org.ap
 
                           // Grab what we need from the passed-down data for 
the document.  These will all become part
                           // of the version string.
-                          String[] pubDates = 
activities.retrieveParentData(urlValue,"pubdate");
-                          String[] sources = 
activities.retrieveParentData(urlValue,"source");
-                          String[] titles = 
activities.retrieveParentData(urlValue,"title");
-                          String[] authorNames = 
activities.retrieveParentData(urlValue,"authorname");
-                          String[] authorEmails = 
activities.retrieveParentData(urlValue,"authoremail");
-                          String[] categories = 
activities.retrieveParentData(urlValue,"category");
-                          String[] descriptions = 
activities.retrieveParentData(urlValue,"description");
+                          pubDates = 
activities.retrieveParentData(urlValue,"pubdate");
+                          sources = 
activities.retrieveParentData(urlValue,"source");
+                          titles = 
activities.retrieveParentData(urlValue,"title");
+                          authorNames = 
activities.retrieveParentData(urlValue,"authorname");
+                          authorEmails = 
activities.retrieveParentData(urlValue,"authoremail");
+                          categories = 
activities.retrieveParentData(urlValue,"category");
+                          descriptions = 
activities.retrieveParentData(urlValue,"description");
                           java.util.Arrays.sort(pubDates);
                           java.util.Arrays.sort(sources);
                           java.util.Arrays.sort(titles);
@@ -1105,7 +1104,7 @@ public class RSSConnector extends org.ap
                         // Do the checksum part, which does not need to be 
parseable.
                         sb.append(new Long(checkSum).toString());
 
-                        rval[i] = sb.toString();
+                        versionString = sb.toString();
                       }
                       finally
                       {
@@ -1115,12 +1114,12 @@ public class RSSConnector extends org.ap
                     catch (java.net.SocketTimeoutException e)
                     {
                       Logging.connectors.warn("RSS: Socket timeout exception 
fetching document contents '"+urlValue+"' - skipping: "+e.getMessage(), e);
-                      rval[i] = null;
+                      versionString = null;
                     }
                     catch (ConnectTimeoutException e)
                     {
                       Logging.connectors.warn("RSS: Connecto timeout exception 
fetching document contents '"+urlValue+"' - skipping: "+e.getMessage(), e);
-                      rval[i] = null;
+                      versionString = null;
                     }
                     catch (InterruptedIOException e)
                     {
@@ -1129,7 +1128,7 @@ public class RSSConnector extends org.ap
                     catch (IOException e)
                     {
                       Logging.connectors.warn("RSS: IO exception fetching 
document contents '"+urlValue+"' - skipping: "+e.getMessage(), e);
-                      rval[i] = null;
+                      versionString = null;
                     }
 
                     break;
@@ -1140,7 +1139,7 @@ public class RSSConnector extends org.ap
                     // Record an *empty* version.
                     // This signals the processDocuments() method that we 
really don't want to ingest this document, but we also don't
                     // want to blow the document out of the queue, since then 
we'd wind up perhaps fetching it multiple times.
-                    rval[i] = "";
+                    versionString = "";
                     break;
                   }
                 }
@@ -1153,342 +1152,205 @@ public class RSSConnector extends org.ap
               {
                 connection.close();
               }
-            }
-          }
-          catch (MalformedURLException e)
-          {
-            Logging.connectors.debug("RSS: URL '"+urlValue+"' is malformed; 
skipping",e);
-            rval[i] = null;
-          }
-        }
-      }
-      finally
-      {
-        int j = 0;
-        while (j < dechromedData.length)
-        {
-          CharacterInput ci = (CharacterInput)dechromedData[j++];
-          if (ci != null)
-            ci.discard();
-        }
-
-      }
-
-      i++;
-    }
-
-    return rval;
-  }
-
-  /** Process a set of documents.
-  * This is the method that should cause each document to be fetched, 
processed, and the results either added
-  * to the queue of documents for the current job, and/or entered into the 
incremental ingestion manager.
-  * The document specification allows this class to filter what is done based 
on the job.
-  *@param documentIdentifiers is the set of document identifiers to process.
-  *@param activities is the interface this method should use to queue up new 
document references
-  * and ingest documents.
-  *@param spec is the document specification.
-  *@param scanOnly is an array corresponding to the document identifiers.  It 
is set to true to indicate when the processing
-  * should only find other references, and should not actually call the 
ingestion methods.
-  */
-  @Override
-  public void processDocuments(String[] documentIdentifiers, String[] 
versions, IProcessActivity activities,
-    DocumentSpecification spec, boolean[] scanOnly, int jobType)
-    throws ManifoldCFException, ServiceInterruption
-  {
-    getSession();
-
-    // The version strings contain the ingest url as well as everything we 
need to determine if this url is a feed or just a document.
-    // So, there is no need to reparse the specification.
-    Filter f = null;
-
-    String[] fixedList = new String[2];
-
-    int i = 0;
-    while (i < documentIdentifiers.length)
-    {
-      String urlValue = documentIdentifiers[i];
-      String version = versions[i];
-
-      if (version.length() == 0)
-      {
-        // This document had an http response incompatible with its existence 
on the web.
-        i++;
-        // Leave document in jobqueue, but do NOT get rid of it, or we will 
wind up seeing it queued again by
-        // somebody else.  We *do* have to signal the document to be removed 
from the index, however, or it will
-        // stick around until the job is deleted.
-        activities.noDocument(urlValue,version);
-        continue;
-      }
-
-      if (Logging.connectors.isDebugEnabled())
-        Logging.connectors.debug("RSS: Processing '"+urlValue+"'");
+                
+              if (versionString == null)
+              {
+                activities.deleteDocument(documentIdentifier);
+                continue;
+              }
+                
+              if (!(versionString.length() == 0 || 
activities.checkDocumentNeedsReindexing(documentIdentifier,versionString)))
+                continue;
+              
+              // Process document!
+              if (Logging.connectors.isDebugEnabled())
+                Logging.connectors.debug("RSS: Processing '"+urlValue+"'");
 
-      // The only links we extract come from documents that we think are RSS 
feeds.
-      // When we think that's the case, we attempt to parse it as RSS XML.
-      if (version.startsWith("-"))
-      {
-        if (Logging.connectors.isDebugEnabled())
-          Logging.connectors.debug("RSS: Interpreting document '"+urlValue+"' 
as a feed");
+              // The only links we extract come from documents that we think 
are RSS feeds.
+              // When we think that's the case, we attempt to parse it as RSS 
XML.
+              if (ingestURL == null)
+              {
+                if (Logging.connectors.isDebugEnabled())
+                  Logging.connectors.debug("RSS: Interpreting document 
'"+urlValue+"' as a feed");
 
-        // We think it is a feed.
-        // The version string does not have anything useful in it.
-        if (f == null)
-          f = new Filter(spec,false);
-
-        // If this is a continuous job, AND scanonly is true, it means that 
the document was either identical to the
-        // previous fetch, or was not fetched at all.  In that case, it may 
not even be there, and we *certainly* don't
-        // want to attempt to process it in any case.
-        //
-
-        // NOTE: I re-enabled the scan permanently because we need the TTL 
value to be set whatever the cost.  If the
-        // TTL value is not set, we default to the specified job's feed-rescan 
time, which is not going to be current enough for some feeds.
-        if (true || scanOnly[i] == false || jobType != JOBMODE_CONTINUOUS)
-        {
-          handleRSSFeedSAX(urlValue,activities,f);
-          if (Logging.connectors.isDebugEnabled())
-            Logging.connectors.debug("RSS: Extraction of feed '"+urlValue+"' 
complete");
+                // We think it is a feed.
+                // If this is a continuous job, AND scanonly is true, it means 
that the document was either identical to the
+                // previous fetch, or was not fetched at all.  In that case, 
it may not even be there, and we *certainly* don't
+                // want to attempt to process it in any case.
+                //
+
+                // NOTE: I re-enabled the scan permanently because we need the 
TTL value to be set whatever the cost.  If the
+                // TTL value is not set, we default to the specified job's 
feed-rescan time, which is not going to be current enough for some feeds.
+                if (true || jobMode != JOBMODE_CONTINUOUS)
+                {
+                  handleRSSFeedSAX(urlValue,activities,f);
+                  if (Logging.connectors.isDebugEnabled())
+                    Logging.connectors.debug("RSS: Extraction of feed 
'"+urlValue+"' complete");
 
-          // Record the feed's version string, so we won't refetch unless 
needed.
-          // This functionality is required for the last ETag and 
Last-Modified fields to be sent to the rss server, and to
-          // keep track of the adaptive parameters.
-          activities.recordDocument(urlValue,version);
-        }
-        else
-        {
-          // The problem here is that we really do need to set the rescan time 
to something reasonable.
-          // But we might not even have read the feed!  So what to do??
-          // One answer is to build a connector-specific table that carries 
the last value of every feed around.
-          // Another answer is to change the version code to always read the 
feed (and the heck with ETag and Last-Modified).
-          if (Logging.connectors.isDebugEnabled())
-            Logging.connectors.debug("RSS: Feed '"+urlValue+"' does not appear 
to differ from previous fetch for a continuous job; not extracting!");
+                  // Record the feed's version string, so we won't refetch 
unless needed.
+                  // This functionality is required for the last ETag and 
Last-Modified fields to be sent to the rss server, and to
+                  // keep track of the adaptive parameters.
+                  activities.recordDocument(documentIdentifier,versionString);
+                }
+                else
+                {
+                  // The problem here is that we really do need to set the 
rescan time to something reasonable.
+                  // But we might not even have read the feed!  So what to do??
+                  // One answer is to build a connector-specific table that 
carries the last value of every feed around.
+                  // Another answer is to change the version code to always 
read the feed (and the heck with ETag and Last-Modified).
+                  if (Logging.connectors.isDebugEnabled())
+                    Logging.connectors.debug("RSS: Feed '"+urlValue+"' does 
not appear to differ from previous fetch for a continuous job; not 
extracting!");
 
-          long currentTime = System.currentTimeMillis();
+                  long currentTime = System.currentTimeMillis();
 
-          Long defaultRescanTime = f.getDefaultRescanTime(currentTime);
+                  Long defaultRescanTime = f.getDefaultRescanTime(currentTime);
 
-          if (defaultRescanTime != null)
-          {
-            Long minimumTime = f.getMinimumRescanTime(currentTime);
-            if (minimumTime != null)
-            {
-              if (defaultRescanTime.longValue() < minimumTime.longValue())
-                defaultRescanTime = minimumTime;
-            }
-          }
+                  if (defaultRescanTime != null)
+                  {
+                    Long minimumTime = f.getMinimumRescanTime(currentTime);
+                    if (minimumTime != null)
+                    {
+                      if (defaultRescanTime.longValue() < 
minimumTime.longValue())
+                        defaultRescanTime = minimumTime;
+                    }
+                  }
 
-          
activities.setDocumentScheduleBounds(urlValue,defaultRescanTime,defaultRescanTime,null,null);
+                  
activities.setDocumentScheduleBounds(urlValue,defaultRescanTime,defaultRescanTime,null,null);
 
-        }
-      }
-      else if (scanOnly[i] == false && version.startsWith("+"))
-      {
-        if (Logging.connectors.isDebugEnabled())
-          Logging.connectors.debug("RSS: Interpreting '"+urlValue+"' as a 
document");
+                }
+              }
+              else
+              {
+                if (Logging.connectors.isDebugEnabled())
+                  Logging.connectors.debug("RSS: Interpreting '"+urlValue+"' 
as a document");
 
+                if (isDataIngestable(activities,urlValue))
+                {
+                  // Treat it as an ingestable document.
+                  
+                  long dataSize = cache.getDataLength(urlValue);
+                  RepositoryDocument rd = new RepositoryDocument();
 
+                  // Set content type
+                  rd.setMimeType(cache.getContentType(urlValue));
 
-        if (isDataIngestable(activities,urlValue))
-        {
-          // Treat it as an ingestable document.
-          // Version *should* start with a "+".
-          ArrayList acls = new ArrayList();
-          StringBuilder denyAclBuffer = new StringBuilder();
-          int startPos = unpackList(acls,version,1,'+');
-          if (startPos < version.length() && version.charAt(startPos++) == '+')
-          {
-            startPos = unpack(denyAclBuffer,version,startPos,'+');
-          }
-          StringBuilder ingestUrlBuffer = new StringBuilder();
-          startPos = unpack(ingestUrlBuffer,version,startPos,'+');
-          String ingestURL = ingestUrlBuffer.toString();
-          ArrayList pubDates = new ArrayList();
-          startPos = unpackList(pubDates,version,startPos,'+');
-          ArrayList titles = new ArrayList();
-          startPos = unpackList(titles,version,startPos,'+');
-          ArrayList sources = new ArrayList();
-          startPos = unpackList(sources,version,startPos,'+');
-          ArrayList categories = new ArrayList();
-          startPos = unpackList(categories,version,startPos,'+');
-          ArrayList descriptions = new ArrayList();
-          startPos = unpackList(descriptions,version,startPos,'+');
-          ArrayList authorNames = new ArrayList();
-          startPos = unpackList(authorNames,version,startPos,'+');
-          ArrayList authorEmails = new ArrayList();
-          startPos = unpackList(authorEmails,version,startPos,'+');
-
-          if (ingestURL.length() > 0)
-          {
-            long dataSize = cache.getDataLength(urlValue);
-            RepositoryDocument rd = new RepositoryDocument();
-
-            // Set content type
-            rd.setMimeType(cache.getContentType(urlValue));
-
-            // Turn into acls and add into description
-            String[] aclArray = new String[acls.size()];
-            int j = 0;
-            while (j < aclArray.length)
-            {
-              aclArray[j] = (String)acls.get(j);
-              j++;
-            }
-            
rd.setSecurityACL(RepositoryDocument.SECURITY_TYPE_DOCUMENT,aclArray);
-
-            // Deny acl too
-            if (denyAclBuffer.length() > 0)
-            {
-              String[] denyAclArray = new String[]{denyAclBuffer.toString()};
-              
rd.setSecurityDenyACL(RepositoryDocument.SECURITY_TYPE_DOCUMENT,denyAclArray);
-            }
-
-            int k;
-            
-            // Loop through the titles to add those to the metadata
-            String[] titleValues = new String[titles.size()];
-            k = 0;
-            while (k < titleValues.length)
-            {
-              titleValues[k] = (String)titles.get(k);
-              k++;
-            }
-            if (k > 0)
-              rd.addField("title",titleValues);
-
-            // Loop through the author names to add those to the metadata
-            String[] authorNameValues = new String[authorNames.size()];
-            k = 0;
-            while (k < authorNameValues.length)
-            {
-              authorNameValues[k] = (String)authorNames.get(k);
-              k++;
-            }
-            if (k > 0)
-              rd.addField("authorname",authorNameValues);
-
-            // Loop through the author emails to add those to the metadata
-            String[] authorEmailValues = new String[authorEmails.size()];
-            k = 0;
-            while (k < authorEmailValues.length)
-            {
-              authorEmailValues[k] = (String)authorEmails.get(k);
-              k++;
-            }
-            if (k > 0)
-              rd.addField("authoremail",authorEmailValues);
-            
-            // Loop through the descriptions to add those to the metadata
-            String[] descriptionValues = new String[descriptions.size()];
-            k = 0;
-            while (k < descriptionValues.length)
-            {
-              descriptionValues[k] = (String)descriptions.get(k);
-              k++;
-            }
-            if (k > 0)
-              rd.addField("summary",descriptionValues);
-
-            // Loop through the sources to add those to the metadata
-            String[] sourceValues = new String[sources.size()];
-            k = 0;
-            while (k < sourceValues.length)
-            {
-              sourceValues[k] = (String)sources.get(k);
-              k++;
-            }
-            if (k > 0)
-              rd.addField("source",sourceValues);
-
-            // Add the categories now
-            String[] categoryValues = new String[categories.size()];
-            k = 0;
-            while (k < categoryValues.length)
-            {
-              categoryValues[k] = (String)categories.get(k);
-              k++;
-            }
-            if (k > 0)
-              rd.addField("category",categoryValues);
-
-            // The pubdates are a ms since epoch value; we want the minimum 
one for the origination time.
-            Long minimumOrigTime = null;
-            String[] pubDateValues = new String[pubDates.size()];
-            String[] pubDateValuesISO = new String[pubDates.size()];
-            TimeZone tz = TimeZone.getTimeZone("UTC");
-            DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
-            df.setTimeZone(tz);
-            k = 0;
-            while (k < pubDates.size())
-            {
-              String pubDate = (String)pubDates.get(k);
-              pubDateValues[k] = pubDate;
-              try
-              {
-                Long pubDateLong = new Long(pubDate);
-                if (minimumOrigTime == null || pubDateLong.longValue() < 
minimumOrigTime.longValue())
-                  minimumOrigTime = pubDateLong;
-                pubDateValuesISO[k] = df.format(new 
Date(pubDateLong.longValue()));
-              }
-              catch (NumberFormatException e)
-              {
-                // Do nothing; the version string seems to not mean anything
-              }
-              k++;
-            }
-            if (k > 0)
-            {
-              rd.addField("pubdate",pubDateValues);
-              rd.addField("pubdateiso",pubDateValuesISO);
-            }
+                  // Turn into acls and add into description
+                  String[] denyAcls;
+                  if (acls == null)
+                    denyAcls = null;
+                  else if (acls.length == 0)
+                    denyAcls = new String[0];
+                  else
+                    denyAcls = new String[]{defaultAuthorityDenyToken};
+                      
+                  if (acls != null && denyAcls != null)
+                    
rd.setSecurity(RepositoryDocument.SECURITY_TYPE_DOCUMENT,acls,denyAcls);
+
+                  if (titles != null && titles.length > 0)
+                    rd.addField("title",titles);
+                  if (authorNames != null && authorNames.length > 0)
+                    rd.addField("authorname",authorNames);
+                  if (authorEmails != null && authorEmails.length > 0)
+                    rd.addField("authoremail",authorEmails);
+                  if (descriptions != null && descriptions.length > 0)
+                    rd.addField("summary",descriptions);
+                  if (sources != null && sources.length > 0)
+                    rd.addField("source",sources);
+                  if (categories != null && categories.length > 0)
+                    rd.addField("category",categories);
+
+                  // The pubdates are a ms since epoch value; we want the 
minimum one for the origination time.
+                  Long minimumOrigTime = null;
+                  if (pubDates != null && pubDates.length > 0)
+                  {
+                    String[] pubDateValuesISO = new String[pubDates.length];
+                    TimeZone tz = TimeZone.getTimeZone("UTC");
+                    DateFormat df = new 
SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
+                    df.setTimeZone(tz);
+                    for (int k = 0; k < pubDates.length; k++)
+                    {
+                      String pubDate = pubDates[k];
+                      try
+                      {
+                        Long pubDateLong = new Long(pubDate);
+                        if (minimumOrigTime == null || pubDateLong.longValue() 
< minimumOrigTime.longValue())
+                          minimumOrigTime = pubDateLong;
+                        pubDateValuesISO[k] = df.format(new 
Date(pubDateLong.longValue()));
+                      }
+                      catch (NumberFormatException e)
+                      {
+                        // Do nothing; the version string seems to not mean 
anything
+                        pubDateValuesISO[k] = "";
+                      }
+                    }
+                    rd.addField("pubdate",pubDates);
+                    rd.addField("pubdateiso",pubDateValuesISO);
+                  }
 
-            if (minimumOrigTime != null)
-              activities.setDocumentOriginationTime(urlValue,minimumOrigTime);
+                  if (minimumOrigTime != null)
+                    
activities.setDocumentOriginationTime(urlValue,minimumOrigTime);
 
-            InputStream is = cache.getData(urlValue);
-            if (is != null)
-            {
-              try
-              {
-                rd.setBinary(is,dataSize);
-                try
-                {
-                  
activities.ingestDocumentWithException(urlValue,version,ingestURL,rd);
-                }
-                catch (IOException e)
-                {
-                  handleIOException(e,"reading data");
-                }
-              }
-              finally
-              {
-                try
-                {
-                  is.close();
+                  InputStream is = cache.getData(urlValue);
+                  if (is != null)
+                  {
+                    try
+                    {
+                      rd.setBinary(is,dataSize);
+                      try
+                      {
+                        
activities.ingestDocumentWithException(documentIdentifier,versionString,ingestURL,rd);
+                      }
+                      catch (IOException e)
+                      {
+                        handleIOException(e,"reading data");
+                      }
+                    }
+                    finally
+                    {
+                      try
+                      {
+                        is.close();
+                      }
+                      catch (IOException e)
+                      {
+                        handleIOException(e,"closing stream");
+                      }
+                    }
+                  }
                 }
-                catch (IOException e)
+                else
                 {
-                  handleIOException(e,"closing stream");
+                  activities.noDocument(documentIdentifier,versionString);
+
+                  if (Logging.connectors.isDebugEnabled())
+                    Logging.connectors.debug("RSS: Skipping document 
'"+urlValue+"' because it cannot be indexed");
                 }
               }
             }
+            catch (MalformedURLException e)
+            {
+              Logging.connectors.debug("RSS: URL '"+urlValue+"' is malformed; 
skipping",e);
+              activities.deleteDocument(documentIdentifier);
+              continue;
+            }
           }
         }
-        else
+        finally
         {
-          activities.noDocument(urlValue,version);
+          for (CharacterInput ci : dechromedData)
+          {
+            if (ci != null)
+              ci.discard();
+          }
 
-          if (Logging.connectors.isDebugEnabled())
-            Logging.connectors.debug("RSS: Skipping document '"+urlValue+"' 
because it cannot be indexed");
         }
       }
-      else
+      finally
       {
-        if (Logging.connectors.isDebugEnabled())
-          Logging.connectors.debug("RSS: Skipping document '"+urlValue+"' 
because it cannot have interesting links");
+        // Remove any fetched documents.
+        cache.deleteData(documentIdentifier);
       }
-      i++;
     }
-
   }
 
   protected static void handleIOException(IOException e, String context)
@@ -1502,31 +1364,6 @@ public class RSSConnector extends org.ap
       throw new ManifoldCFException("IO error "+context+": "+e.getMessage(),e);
   }
   
-  /** Free a set of documents.  This method is called for all documents whose 
versions have been fetched using
-  * the getDocumentVersions() method, including those that returned null 
versions.  It may be used to free resources
-  * committed during the getDocumentVersions() method.  It is guaranteed to be 
called AFTER any calls to
-  * processDocuments() for the documents in question.
-  *@param documentIdentifiers is the set of document identifiers.
-  *@param versions is the corresponding set of version identifiers (individual 
identifiers may be null).
-  */
-  @Override
-  public void releaseDocumentVersions(String[] documentIdentifiers, String[] 
versions)
-    throws ManifoldCFException
-  {
-    int i = 0;
-    while (i < documentIdentifiers.length)
-    {
-      String version = versions[i];
-      if (version != null)
-
-      {
-        String urlValue = documentIdentifiers[i];
-        cache.deleteData(urlValue);
-      }
-      i++;
-    }
-  }
-
   // UI support methods.
   //
   // These support methods come in two varieties.  The first bunch is involved 
in setting up connection configuration information.  The second bunch


Reply via email to