manifoldcf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kwri...@apache.org
Subject svn commit: r1647585 [1/2] - in /manifoldcf/trunk: ./ connectors/email/ connectors/email/connector/src/main/java/org/apache/manifoldcf/crawler/notifications/ connectors/email/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/notifications/ ...
Date Tue, 23 Dec 2014 14:46:44 GMT
Author: kwright
Date: Tue Dec 23 14:46:43 2014
New Revision: 1647585

URL: http://svn.apache.org/r1647585
Log:
Implement CONNECTORS-1119.

Added:
    manifoldcf/trunk/connectors/email/connector/src/main/java/org/apache/manifoldcf/crawler/notifications/
      - copied from r1647584, manifoldcf/branches/CONNECTORS-1119/connectors/email/connector/src/main/java/org/apache/manifoldcf/crawler/notifications/
    manifoldcf/trunk/connectors/email/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/notifications/
      - copied from r1647584, manifoldcf/branches/CONNECTORS-1119/connectors/email/connector/src/main/native2ascii/org/apache/manifoldcf/crawler/notifications/
    manifoldcf/trunk/connectors/email/connector/src/main/resources/org/apache/manifoldcf/crawler/notifications/
      - copied from r1647584, manifoldcf/branches/CONNECTORS-1119/connectors/email/connector/src/main/resources/org/apache/manifoldcf/crawler/notifications/
    manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editnotification.jsp
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/crawler-ui/src/main/webapp/editnotification.jsp
    manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listnotifications.jsp
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/crawler-ui/src/main/webapp/listnotifications.jsp
    manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewnotification.jsp
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/crawler-ui/src/main/webapp/viewnotification.jsp
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/INotificationConnection.java
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/INotificationConnection.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/INotificationConnectionManager.java
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/INotificationConnectionManager.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/INotificationConnector.java
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/INotificationConnector.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/INotificationConnectorManager.java
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/INotificationConnectorManager.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/INotificationConnectorPool.java
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/INotificationConnectorPool.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/NotificationConnectionManagerFactory.java
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/NotificationConnectionManagerFactory.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/NotificationConnectorFactory.java
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/NotificationConnectorFactory.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/NotificationConnectorManagerFactory.java
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/NotificationConnectorManagerFactory.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/NotificationConnectorPoolFactory.java
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/NotificationConnectorPoolFactory.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/NotificationManager.java
      - copied unchanged from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/NotificationManager.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/notification/
      - copied from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/notification/
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/notificationconnectorpool/
      - copied from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/notificationconnectorpool/
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/notificationconnmgr/
      - copied from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/notificationconnmgr/
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/notifications/
      - copied from r1647584, manifoldcf/branches/CONNECTORS-1119/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/notifications/
Modified:
    manifoldcf/trunk/   (props changed)
    manifoldcf/trunk/CHANGES.txt
    manifoldcf/trunk/connectors/email/build.xml
    manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java
    manifoldcf/trunk/framework/buildfiles/connector-build.xml
    manifoldcf/trunk/framework/combined-service/src/main/java/org/apache/manifoldcf/combinedservice/IdleCleanupThread.java
    manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java
    manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editjob.jsp
    manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editoutput.jsp
    manifoldcf/trunk/framework/crawler-ui/src/main/webapp/edittransformation.jsp
    manifoldcf/trunk/framework/crawler-ui/src/main/webapp/execute.jsp
    manifoldcf/trunk/framework/crawler-ui/src/main/webapp/navigation.jsp
    manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewjob.jsp
    manifoldcf/trunk/framework/example-common/connectors.xml
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/CacheKeyFactory.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IJobDescription.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IJobManager.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobDescription.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobManager.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/Jobs.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/CrawlerAgent.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/IdleCleanupThread.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/JobNotificationThread.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/JobResetThread.java
    manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/ManifoldCF.java
    manifoldcf/trunk/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_en_US.properties
    manifoldcf/trunk/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_ja_JP.properties
    manifoldcf/trunk/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_zh_CN.properties

Propchange: manifoldcf/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Dec 23 14:46:43 2014
@@ -45,6 +45,7 @@
 /manifoldcf/branches/CONNECTORS-1100:1637693-1640317
 /manifoldcf/branches/CONNECTORS-1104:1640149-1640198
 /manifoldcf/branches/CONNECTORS-1118:1644108-1644398
+/manifoldcf/branches/CONNECTORS-1119:1645497-1647584
 /manifoldcf/branches/CONNECTORS-120:1406712-1407974,1407982-1411043,1411049-1416451
 /manifoldcf/branches/CONNECTORS-120-1:1416450-1417056
 /manifoldcf/branches/CONNECTORS-13:1525862-1527182,1539324-1541634

Modified: manifoldcf/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/CHANGES.txt?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/CHANGES.txt (original)
+++ manifoldcf/trunk/CHANGES.txt Tue Dec 23 14:46:43 2014
@@ -3,6 +3,9 @@ $Id$
 
 ======================= 2.1-dev =====================
 
+CONNECTORS-1119: Add support for notification connectors, and
+an email notification connector.
+(Karl Wright)
 
 ======================= Release 2.0 =====================
 

Modified: manifoldcf/trunk/connectors/email/build.xml
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/connectors/email/build.xml?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/connectors/email/build.xml (original)
+++ manifoldcf/trunk/connectors/email/build.xml Tue Dec 23 14:46:43 2014
@@ -35,6 +35,10 @@ limitations under the License.
             <param name="connector-label" value="EMail"/>
             <param name="connector-class" value="org.apache.manifoldcf.crawler.connectors.email.EmailConnector"/>
         </antcall>
+        <antcall target="general-add-notification-connector">
+            <param name="connector-label" value="EMail"/>
+            <param name="connector-class" value="org.apache.manifoldcf.crawler.notifications.email.EmailConnector"/>
+        </antcall>
     </target>
 
 </project>
\ No newline at end of file

Modified: manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java (original)
+++ manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java Tue Dec 23 14:46:43 2014
@@ -53,6 +53,7 @@ public class IdleCleanupThread extends T
       IThreadContext threadContext = ThreadContextFactory.make();
       
       IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
+      INotificationConnectorPool notificationConnectorPool = NotificationConnectorPoolFactory.make(threadContext);
       IOutputConnectorPool outputConnectorPool = OutputConnectorPoolFactory.make(threadContext);
       ITransformationConnectorPool transformationConnectorPool = TransformationConnectorPoolFactory.make(threadContext);
       IAuthorityConnectorPool authorityConnectorPool = AuthorityConnectorPoolFactory.make(threadContext);
@@ -66,6 +67,7 @@ public class IdleCleanupThread extends T
         {
           // Do the cleanup
           repositoryConnectorPool.pollAllConnectors();
+          notificationConnectorPool.pollAllConnectors();
           outputConnectorPool.pollAllConnectors();
           transformationConnectorPool.pollAllConnectors();
           authorityConnectorPool.pollAllConnectors();

Modified: manifoldcf/trunk/framework/buildfiles/connector-build.xml
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/buildfiles/connector-build.xml?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/buildfiles/connector-build.xml (original)
+++ manifoldcf/trunk/framework/buildfiles/connector-build.xml Tue Dec 23 14:46:43 2014
@@ -886,6 +886,25 @@
     <target name="general-add-transformation-connector" depends="general-add-transformation-connector-commented,general-add-transformation-connector-non-commented,general-add-transformation-connector-proprietary-commented,general-add-transformation-connector-proprietary-non-commented">
     </target>
 
+    <target name="general-add-notification-connector-commented" depends="general-connector-runnable-check" unless="is-runnable">
+        <replace file="${mcf-dist}/connectors.xml" token="&lt;!-- Add your notification connectors here --&gt;" value="&lt;!-- Add your notification connectors here --&gt;&#0010;  &lt;!--notificationconnector name=&quot;${connector-label}&quot; class=&quot;${connector-class}&quot;/--&gt;"/>
+    </target>
+
+    <target name="general-add-notification-connector-non-commented" depends="general-connector-runnable-check" if="is-runnable">
+        <replace file="${mcf-dist}/connectors.xml" token="&lt;!-- Add your notification connectors here --&gt;" value="&lt;!-- Add your notification connectors here --&gt;&#0010;  &lt;notificationconnector name=&quot;${connector-label}&quot; class=&quot;${connector-class}&quot;/&gt;"/>
+    </target>
+
+    <target name="general-add-notification-connector-proprietary-commented" depends="general-connector-proprietary-runnable-check" unless="is-proprietary-runnable">
+        <replace file="${mcf-dist}/connectors-proprietary.xml" token="&lt;!-- Add your notification connectors here --&gt;" value="&lt;!-- Add your notification connectors here --&gt;&#0010;  &lt;!--notificationconnector name=&quot;${connector-label}&quot; class=&quot;${connector-class}&quot;/--&gt;"/>
+    </target>
+
+    <target name="general-add-notification-connector-proprietary-non-commented" depends="general-connector-proprietary-runnable-check" if="is-proprietary-runnable">
+        <replace file="${mcf-dist}/connectors-proprietary.xml" token="&lt;!-- Add your notification connectors here --&gt;" value="&lt;!-- Add your notification connectors here --&gt;&#0010;  &lt;notificationconnector name=&quot;${connector-label}&quot; class=&quot;${connector-class}&quot;/&gt;"/>
+    </target>
+
+    <target name="general-add-notification-connector" depends="general-add-notification-connector-commented,general-add-notification-connector-non-commented,general-add-notification-connector-proprietary-commented,general-add-notification-connector-proprietary-non-commented">
+    </target>
+
     <target name="general-add-repository-connector-commented" depends="general-connector-runnable-check" unless="is-runnable">
         <replace file="${mcf-dist}/connectors.xml" token="&lt;!-- Add your repository connectors here --&gt;" value="&lt;!-- Add your repository connectors here --&gt;&#0010;  &lt;!--repositoryconnector name=&quot;${connector-label}&quot; class=&quot;${connector-class}&quot;/--&gt;"/>
     </target>

Modified: manifoldcf/trunk/framework/combined-service/src/main/java/org/apache/manifoldcf/combinedservice/IdleCleanupThread.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/combined-service/src/main/java/org/apache/manifoldcf/combinedservice/IdleCleanupThread.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/combined-service/src/main/java/org/apache/manifoldcf/combinedservice/IdleCleanupThread.java (original)
+++ manifoldcf/trunk/framework/combined-service/src/main/java/org/apache/manifoldcf/combinedservice/IdleCleanupThread.java Tue Dec 23 14:46:43 2014
@@ -53,6 +53,7 @@ public class IdleCleanupThread extends T
       IThreadContext threadContext = ThreadContextFactory.make();
       
       IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
+      INotificationConnectorPool notificationConnectorPool = NotificationConnectorPoolFactory.make(threadContext);
       IOutputConnectorPool outputConnectorPool = OutputConnectorPoolFactory.make(threadContext);
       ITransformationConnectorPool transformationConnectorPool = TransformationConnectorPoolFactory.make(threadContext);
       IAuthorityConnectorPool authorityConnectorPool = AuthorityConnectorPoolFactory.make(threadContext);
@@ -66,6 +67,7 @@ public class IdleCleanupThread extends T
         {
           // Do the cleanup
           repositoryConnectorPool.pollAllConnectors();
+          notificationConnectorPool.pollAllConnectors();
           outputConnectorPool.pollAllConnectors();
           transformationConnectorPool.pollAllConnectors();
           authorityConnectorPool.pollAllConnectors();

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java Tue Dec 23 14:46:43 2014
@@ -53,6 +53,7 @@ public class IdleCleanupThread extends T
       IThreadContext threadContext = ThreadContextFactory.make();
       
       IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
+      INotificationConnectorPool notificationConnectorPool = NotificationConnectorPoolFactory.make(threadContext);
       IOutputConnectorPool outputConnectorPool = OutputConnectorPoolFactory.make(threadContext);
       ITransformationConnectorPool transformationConnectorPool = TransformationConnectorPoolFactory.make(threadContext);
       IAuthorityConnectorPool authorityConnectorPool = AuthorityConnectorPoolFactory.make(threadContext);
@@ -66,6 +67,7 @@ public class IdleCleanupThread extends T
         {
           // Do the cleanup
           repositoryConnectorPool.pollAllConnectors();
+          notificationConnectorPool.pollAllConnectors();
           outputConnectorPool.pollAllConnectors();
           transformationConnectorPool.pollAllConnectors();
           authorityConnectorPool.pollAllConnectors();

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editjob.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editjob.jsp?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editjob.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editjob.jsp Tue Dec 23 14:46:43 2014
@@ -33,6 +33,8 @@
 	IJobManager manager = JobManagerFactory.make(threadContext);
 	IRepositoryConnectionManager connMgr = RepositoryConnectionManagerFactory.make(threadContext);
 	IRepositoryConnection[] connList = connMgr.getAllConnections();
+	INotificationConnectionManager notificationMgr = NotificationConnectionManagerFactory.make(threadContext);
+	INotificationConnection[] notificationList = notificationMgr.getAllConnections();
 	IOutputConnectionManager outputMgr = OutputConnectionManagerFactory.make(threadContext);
 	IOutputConnection[] outputList = outputMgr.getAllConnections();
 	ITransformationConnectionManager transformationMgr = TransformationConnectionManagerFactory.make(threadContext);
@@ -40,6 +42,7 @@
 
 	IOutputConnectorPool outputConnectorPool = OutputConnectorPoolFactory.make(threadContext);
 	IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
+	INotificationConnectorPool notificationConnectorPool = NotificationConnectorPoolFactory.make(threadContext);
 	ITransformationConnectorPool transformationConnectorPool = TransformationConnectorPoolFactory.make(threadContext);
 
 	// Figure out tab name and sequence number
@@ -89,6 +92,10 @@
 	int[] pipelinePrerequisites = new int[0];
 	Specification[] pipelineSpecifications = new Specification[0];
 	
+	String[] notificationConnectionNames = new String[0];
+	String[] notificationDescriptions = new String[0];
+	Specification[] notificationSpecifications = new Specification[0];
+	
 	ArrayList scheduleRecords = new ArrayList();
 
 	EnumeratedValues dayOfWeek = null;
@@ -139,6 +146,16 @@
 			pipelinePrerequisites[j] = job.getPipelineStagePrerequisite(j);
 			pipelineSpecifications[j] = job.getPipelineStageSpecification(j);
 		}
+		notificationConnectionNames = new String[job.countNotifications()];
+		notificationDescriptions = new String[job.countNotifications()];
+		notificationSpecifications = new Specification[job.countNotifications()];
+		for (int j = 0; j < job.countNotifications(); j++)
+		{
+			notificationConnectionNames[j] = job.getNotificationConnectionName(j);
+			notificationDescriptions[j] = job.getNotificationDescription(j);
+			notificationSpecifications[j] = job.getNotificationSpecification(j);
+		}
+		
 		type = job.getType();
 		startMethod = job.getStartMethod();
 		hopcountMode = job.getHopcountMode();
@@ -204,11 +221,19 @@
 	String saveCheckMethod = "checkSpecificationForSave";
 	String[] pipelineCheckMethods = new String[pipelineConnectionNames.length];
 	String[] pipelineCheckForSaveMethods = new String[pipelineConnectionNames.length];
+	String[] notificationCheckMethods = new String[notificationConnectionNames.length];
+	String[] notificationCheckForSaveMethods = new String[notificationConnectionNames.length];
+	
 	for (int j = 0; j < pipelineConnectionNames.length; j++)
 	{
 		pipelineCheckMethods[j] = "unknown";
 		pipelineCheckForSaveMethods[j] = "unknown";
 	}
+	for (int j = 0; j < notificationConnectionNames.length; j++)
+	{
+		notificationCheckMethods[j] = "unknown";
+		notificationCheckForSaveMethods[j] = "unknown";
+	}
 	
 	if (connection != null)
 	{
@@ -250,6 +275,20 @@
 		}
 	}
 
+	for (int j = 0; j < notificationConnectionNames.length; j++)
+	{
+		INotificationConnection notificationConnection = notificationMgr.load(notificationConnectionNames[j]);
+		if (notificationConnection != null)
+		{
+			INotificationConnector notificationConnector = NotificationConnectorFactory.getConnectorNoCheck(notificationConnection.getClassName());
+			if (notificationConnector != null)
+			{
+				notificationCheckMethods[j] = notificationConnector.getFormCheckJavascriptMethodName(1+pipelineConnectionNames.length+j);
+				notificationCheckForSaveMethods[j] = notificationConnector.getFormPresaveCheckJavascriptMethodName(1+pipelineConnectionNames.length+j);
+			}
+
+		}
+	}
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
@@ -346,6 +385,16 @@
 			}
 <%
 	}
+	for (int j = 0; j < notificationCheckForSaveMethods.length; j++)
+	{
+%>
+			if (window.<%=notificationCheckForSaveMethods[j]%>)
+			{
+				if (<%=notificationCheckForSaveMethods[j]%>() == false)
+					return;
+			}
+<%
+	}
 %>
 			if (window.<%=saveCheckMethod%>)
 			{
@@ -413,7 +462,28 @@
 		else
 			postFormSetAnchor("pipeline_"+(n-1)+"_tag");
 	}
+
+	function AppendNotification()
+	{
+		if (editjob.notification_connectionname.value == "")
+		{
+			alert("<%=Messages.getBodyJavascriptString(pageContext.getRequest().getLocale(),"editjob.SelectANotificationConnectionName")%>");
+			editjob.notification_connectionname.focus();
+			return;
+		}
+		document.editjob.notification_op.value="Add";
+		postFormSetAnchor("notification_tag");
+	}
 	
+	function DeleteNotification(n)
+	{
+		eval("document.editjob.notification_"+n+"_op.value = 'Delete'");
+		if (n == 0)
+			postFormSetAnchor("notification_tag");
+		else
+			postFormSetAnchor("notification_"+(n-1)+"_tag");
+	}
+
 	function AddScheduledTime()
 	{
 		if (editjob.duration.value != "" && !isInteger(editjob.duration.value))
@@ -460,6 +530,16 @@
 		}
 <%
 	}
+	for (int j = 0; j < notificationCheckMethods.length; j++)
+	{
+%>
+		if (window.<%=notificationCheckMethods[j]%>)
+		{
+			if (<%=notificationCheckMethods[j]%>() == false)
+				return false;
+		}
+<%
+	}
 %>
 		// Check the connector part
 		if (window.<%=checkMethod%>)
@@ -638,6 +718,33 @@
 	
 %>
 
+<%
+	for (int j = 0; j < notificationConnectionNames.length; j++)
+	{
+		INotificationConnection notificationConnection = notificationMgr.load(notificationConnectionNames[j]);
+		if (notificationConnection != null)
+		{
+			INotificationConnector notificationConnector = notificationConnectorPool.grab(notificationConnection);
+			if (notificationConnector != null)
+			{
+				try
+				{
+					notificationConnector.outputSpecificationHeader(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),notificationSpecifications[j],1+pipelineConnectionNames.length+j,tabsArray);
+				}
+				finally
+				{
+					notificationConnectorPool.release(notificationConnection,notificationConnector);
+				}
+			}
+		}
+		Integer connectionSequenceNumber = new Integer(1+pipelineConnectionNames.length+j);
+		while (sequenceArray.size() < tabsArray.size())
+		{
+			sequenceArray.add(connectionSequenceNumber);
+		}
+	}
+%>
+
 </head>
 
 <body class="standardbody">
@@ -1081,7 +1188,94 @@
 					</table>
 				</td>
 			</tr>
-			
+
+<%
+		alreadyPresent = new HashSet<String>();
+		for (int j = 0; j < notificationConnectionNames.length; j++)
+		{
+			alreadyPresent.add(notificationConnectionNames[j]);
+		}
+		if (notificationList.length > 0)
+		{
+%>
+			<tr>
+				<td colspan="1" class="description"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.NotificationsColon")%></nobr></td>
+				<td class="boxcell" colspan="3">
+					<table class="formtable">
+						<tr class="formheaderrow">
+							<td class="formcolumnheader">
+								<input name="notification_count" type="hidden" value="<%=notificationConnectionNames.length%>"/>
+							</td>
+							<td class="formcolumnheader"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.StageNumber")%></nobr></td>
+							<td class="formcolumnheader"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.NotificationDescription")%></nobr></td>
+							<td class="formcolumnheader"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.NotificationConnectionName")%></nobr></td>
+						</tr>
+<%
+			rowCounter = 0;
+			for (int j = 0; j < notificationConnectionNames.length; j++)
+			{
+				String notificationConnectionName = notificationConnectionNames[j];
+				String notificationDescription = notificationDescriptions[j];
+				if (notificationDescription == null)
+					notificationDescription = "";
+%>
+						<tr class="<%=((rowCounter++ % 2)==0)?"evenformrow":"oddformrow"%>">
+							<td class="formcolumncell">
+								<input name="notification_<%=j%>_op" type="hidden" value="Continue"/>
+								<a name="notification_<%=j%>_tag"/>
+								<input type="button" value="<%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.Delete")%>" alt='<%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.Deletenotification")%>' onclick="javascript:DeleteNotification(<%=j%>);"/>
+							</td>
+							<td class="formcolumncell"><%=(j+pipelineConnectionNames.length+2)%>.</td>
+							<td class="formcolumncell">
+								<input name="notification_<%=j%>_description" type="text" size="30" value="<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(notificationDescription)%>"/>
+							</td>
+							<td class="formcolumncell">
+								<nobr><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(notificationConnectionName)%></nobr>
+								<input name="notification_<%=j%>_connectionname" type="hidden" value="<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(notificationConnectionName)%>"/>
+							</td>
+						</tr>
+<%
+			}
+			if (notificationList.length != alreadyPresent.size())
+			{
+%>
+						<tr class="formrow"><td class="formseparator" colspan="4"><hr/></td></tr>
+						<tr class="formrow">
+							<td class="formcolumncell">
+								<a name="notification_tag"/>
+								<input type="button" value='<%=Messages.getAttributeString(pageContext.getRequest().getLocale(),"editjob.AddNotification")%>' alt='<%=Messages.getAttributeString(pageContext.getRequest().getLocale(),"editjob.AddANotification")%>' onclick="javascript:AppendNotification();"/>
+								<input name="notification_op" type="hidden" value="Continue"/>
+							</td>
+							<td class="formcolumncell"></td>
+							<td class="formcolumncell">
+								<input name="notification_description" type="text" size="30" value=""/>
+							</td>
+							<td class="formcolumncell">
+								<select name="notification_connectionname" size="1">
+									<option selected="selected" value="">-- <%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.NoneSelected")%> --</option>
+<%
+				for (INotificationConnection conn : notificationList)
+				{
+					if (!alreadyPresent.contains(conn.getName()))
+					{
+%>
+									<option value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(conn.getName())%>'><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(conn.getName())%></option>
+<%
+					}
+				}
+%>
+								</select>
+							</td>
+						</tr>
+<%
+			}
+%>
+					</table>
+				</td>
+			</tr>
+<%
+		}
+%>
 			<tr><td class="separator" colspan="4"><hr/></td></tr>
 			
 			<tr>
@@ -1117,6 +1311,7 @@
 %>
 		  <input type="hidden" name="connectionname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(connectionName)%>'/>
 		  <input type="hidden" name="pipeline_count" value="<%=pipelineConnectionNames.length%>"/>
+		  <input type="hidden" name="notification_count" value="<%=notificationConnectionNames.length%>"/>
 <%
 		for (int j = 0; j < pipelineConnectionNames.length; j++)
 		{
@@ -1131,6 +1326,18 @@
 		  <input type="hidden" name="pipeline_<%=j%>_description" value="<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(pipelineDescription)%>"/>
 <%
 		}
+		for (int j = 0; j < notificationConnectionNames.length; j++)
+		{
+			String notificationConnectionName = notificationConnectionNames[j];
+			String notificationDescription = notificationDescriptions[j];
+			if (notificationDescription == null)
+				notificationDescription = "";
+%>
+		  <input type="hidden" name="notification_<%=j%>_connectionname" value="<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(notificationConnectionName)%>"/>
+		  <input type="hidden" name="notification_<%=j%>_description" value="<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(notificationDescription)%>"/>
+<%
+		}
+
 %>
 		  <input type="hidden" name="priority" value='<%=priority%>'/>
 		  <input type="hidden" name="startmethod" value='<%=startMethod%>'/>
@@ -1656,6 +1863,26 @@
 				}
 			}
 		}
+	}
+	
+	for (int j = 0; j < notificationConnectionNames.length; j++)
+	{
+		INotificationConnection notificationConnection = notificationMgr.load(notificationConnectionNames[j]);
+		if (notificationConnection != null)
+		{
+			INotificationConnector notificationConnector = notificationConnectorPool.grab(notificationConnection);
+			if (notificationConnector != null)
+			{
+				try
+				{
+					notificationConnector.outputSpecificationBody(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),notificationSpecifications[j],1+pipelineConnectionNames.length+j,tabSequenceInt,tabName);
+				}
+				finally
+				{
+					notificationConnectorPool.release(notificationConnection,notificationConnector);
+				}
+			}
+		}
 	}
 
 %>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editoutput.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editoutput.jsp?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editoutput.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editoutput.jsp Tue Dec 23 14:46:43 2014
@@ -232,7 +232,7 @@
 	{
 %>
 	<p class="windowtitle"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editoutput.EditOutputConnection")%></p>
-	<table class="displaytable"><tr><td class="message">No output connectors registered</td></tr></table>
+	<table class="displaytable"><tr><td class="message"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editoutput.NoOutputConnectorsRegistered")%></td></tr></table>
 <%
 	}
 	else

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/edittransformation.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/edittransformation.jsp?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/edittransformation.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/edittransformation.jsp Tue Dec 23 14:46:43 2014
@@ -231,8 +231,8 @@
 	if (set.getRowCount() == 0)
 	{
 %>
-	<p class="windowtitle"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"edittransformation.EditTransformationConnection")%></p>
-	<table class="displaytable"><tr><td class="message">No transformation connectors registered</td></tr></table>
+	<p class="windowtitle"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"edittransformation.EditTransformationConnection2")%></p>
+	<table class="displaytable"><tr><td class="message"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"edittransformation.NoTransformationConnectorsRegistered")%></td></tr></table>
 <%
 	}
 	else

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/execute.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/execute.jsp?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/execute.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/execute.jsp Tue Dec 23 14:46:43 2014
@@ -47,6 +47,7 @@
 		IJobManager manager = JobManagerFactory.make(threadContext);
 		IAuthorityGroupManager authGroupManager = AuthorityGroupManagerFactory.make(threadContext);
 		IRepositoryConnectionManager connManager = RepositoryConnectionManagerFactory.make(threadContext);
+		INotificationConnectionManager notificationManager = NotificationConnectionManagerFactory.make(threadContext);
 		IAuthorityConnectionManager authConnManager = AuthorityConnectionManagerFactory.make(threadContext);
 		IMappingConnectionManager mappingConnManager = MappingConnectionManagerFactory.make(threadContext);
 		IOutputConnectionManager outputManager = OutputConnectionManagerFactory.make(threadContext);
@@ -55,6 +56,7 @@
 		IOutputConnectorPool outputConnectorPool = OutputConnectorPoolFactory.make(threadContext);
 		ITransformationConnectorPool transformationConnectorPool = TransformationConnectorPoolFactory.make(threadContext);
 		IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
+		INotificationConnectorPool notificationConnectorPool = NotificationConnectorPoolFactory.make(threadContext);
 		
 		String type = variableContext.getParameter("type");
 		String op = variableContext.getParameter("op");
@@ -865,6 +867,121 @@
 <%
 			}
 		}
+		else if (type != null && op != null && type.equals("notification"))
+		{
+			// -- Notification connection editing operations --
+			if (op.equals("Save") || op.equals("Continue"))
+			{
+				try
+				{
+					// Set up a connection object that is a merge of an existing connection object plus what was posted.
+					INotificationConnection connection = null;
+					boolean isNew = true;
+					String x = variableContext.getParameter("isnewconnection");
+					if (x != null)
+						isNew = x.equals("true");
+
+					String connectionName = variableContext.getParameter("connname");
+					// If the connectionname is not null, load the connection description and prepopulate everything with what comes from it.
+					if (connectionName != null && connectionName.length() > 0 && !isNew)
+					{
+						connection = notificationManager.load(connectionName);
+					}
+					
+					if (connection == null)
+					{
+						connection = notificationManager.create();
+						if (connectionName != null && connectionName.length() > 0)
+							connection.setName(connectionName);
+					}
+
+					// Gather all the data from the form.
+					connection.setIsNew(isNew);
+					x = variableContext.getParameter("description");
+					if (x != null)
+						connection.setDescription(x);
+					x = variableContext.getParameter("classname");
+					if (x != null)
+						connection.setClassName(x);
+					x = variableContext.getParameter("maxconnections");
+					if (x != null && x.length() > 0)
+						connection.setMaxConnections(Integer.parseInt(x));
+
+					String error = NotificationConnectorFactory.processConfigurationPost(threadContext,connection.getClassName(),variableContext,pageContext.getRequest().getLocale(),connection.getConfigParams());
+					
+					if (error != null)
+					{
+						variableContext.setParameter("text",error);
+						variableContext.setParameter("target","listnotifications.jsp");
+%>
+						<jsp:forward page="error.jsp"/>
+<%
+					}
+					
+					if (op.equals("Continue"))
+					{
+						threadContext.save("ConnectionObject",connection);
+%>
+						<jsp:forward page="editnotification.jsp"/>
+<%
+					}
+					else if (op.equals("Save"))
+					{
+						notificationManager.save(connection);
+						variableContext.setParameter("connname",connectionName);
+%>
+						<jsp:forward page="viewnotification.jsp"/>
+<%
+					}
+				}
+				catch (ManifoldCFException e)
+				{
+					e.printStackTrace();
+					variableContext.setParameter("text",e.getMessage());
+					variableContext.setParameter("target","listnotifications.jsp");
+%>
+					<jsp:forward page="error.jsp"/>
+<%
+				}
+			}
+			else if (op.equals("Delete"))
+			{
+				try
+				{
+					String connectionName = variableContext.getParameter("connname");
+					if (connectionName == null)
+						throw new ManifoldCFException("Missing connection parameter");
+					notificationManager.delete(connectionName);
+%>
+					<jsp:forward page="listnotifications.jsp"/>
+<%
+				}
+				catch (ManifoldCFException e)
+				{
+					e.printStackTrace();
+					variableContext.setParameter("text",e.getMessage());
+					variableContext.setParameter("target","listnotifications.jsp");
+%>
+					<jsp:forward page="error.jsp"/>
+<%
+				}
+			}
+			else if (op.equals("Cancel"))
+			{
+%>
+				<jsp:forward page="listnotifications.jsp"/>
+<%
+			}
+			else
+			{
+				// Error
+				variableContext.setParameter("text","Illegal parameter to notification connection execution page");
+				variableContext.setParameter("target","listnotifications.jsp");
+%>
+				<jsp:forward page="error.jsp"/>
+<%
+			}
+		}
 		else if (type != null && op != null && type.equals("job"))
 		{
 			// -- Job editing operations --
@@ -918,6 +1035,21 @@
 							job.addPipelineStage(precedent, isOutput, connectionName, description);
 						}
 					}
+					x = variableContext.getParameter("notification_count");
+					if (x != null)
+					{
+						// Do we need to keep the old specifications around, or can we destroy them?
+						// Not clear that retention is required., so I'm not wasting time trying to implement that.
+						int count = Integer.parseInt(x);
+						job.clearNotifications();
+						for (int j = 0; j < count; j++)
+						{
+							// Gather everything first; we'll look at edits later
+							String connectionName = variableContext.getParameter("notification_"+j+"_connectionname");
+							String description = variableContext.getParameter("notification_"+j+"_description");
+							job.addNotification(connectionName, description);
+						}
+					}
 
 					x = variableContext.getParameter("schedulerecords");
 					String[] y;
@@ -1238,6 +1370,34 @@
 						}
 					}
 
+					for (int j = 0; j < job.countNotifications(); j++)
+					{
+						INotificationConnection notificationConnection = notificationManager.load(job.getNotificationConnectionName(j));
+						if (notificationConnection != null)
+						{
+							INotificationConnector notificationConnector = notificationConnectorPool.grab(notificationConnection);
+							if (notificationConnector != null)
+							{
+								try
+								{
+									String error = notificationConnector.processSpecificationPost(variableContext,pageContext.getRequest().getLocale(),job.getNotificationSpecification(j),1+job.countPipelineStages()+j);
+									if (error != null)
+									{
+										variableContext.setParameter("text",error);
+										variableContext.setParameter("target","listjobs.jsp");
+%>
+									<jsp:forward page="error.jsp"/>
+<%
+									}
+								}
+								finally
+								{
+									notificationConnectorPool.release(notificationConnection,notificationConnector);
+								}
+							}
+						}
+					}
+					
 					// Now, after gathering is complete, consider doing changes to the pipeline.
 					int currentStage = 0;
 					for (int j = 0; j < job.countPipelineStages(); j++)
@@ -1268,6 +1428,7 @@
 						else
 							currentStage++;
 					}
+
 					x = variableContext.getParameter("output_op");
 					if (x != null && x.equals("Add"))
 					{
@@ -1278,6 +1439,28 @@
 						job.addPipelineStage(precedent,true,connectionName,description);
 					}
 					
+					currentStage = 0;
+					for (int j = 0; j < job.countNotifications(); j++)
+					{
+						// Look at the operation
+						x = variableContext.getParameter("notification_"+j+"_op");
+						if (x != null && x.equals("Delete"))
+						{
+							// Delete this pipeline stage (and rewire other stages according to rules)
+							job.deleteNotification(currentStage);
+						}
+						else
+							currentStage++;
+					}
+					x = variableContext.getParameter("notification_op");
+					if (x != null && x.equals("Add"))
+					{
+						// Append a new stage at the end
+						String connectionName = variableContext.getParameter("notification_connectionname");
+						String description = variableContext.getParameter("notification_description");
+						job.addNotification(connectionName,description);
+					}
+
 					if (op.equals("Continue"))
 					{
 						threadContext.save("JobObject",job);

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/navigation.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/navigation.jsp?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/navigation.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/navigation.jsp Tue Dec 23 14:46:43 2014
@@ -54,6 +54,9 @@
 	<li class="menuitem">
 		<nobr><a class="menulink" href="listconnections.jsp" alt="<%=Messages.getAttributeString(pageContext.getRequest().getLocale(),"navigation.Listrepositoryconnections")%>"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"navigation.ListRepositoryConnections")%></a></nobr>
 	</li>
+	<li class="menuitem">
+		<nobr><a class="menulink" href="listnotifications.jsp" alt="<%=Messages.getAttributeString(pageContext.getRequest().getLocale(),"navigation.Listnotificationconnections")%>"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"navigation.ListNotificationConnections")%></a></nobr>
+	</li>
 </ul>
 <p class="menumain"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"navigation.Jobs")%></nobr></p>
 <ul class="menusecond">

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewjob.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewjob.jsp?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewjob.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewjob.jsp Tue Dec 23 14:46:43 2014
@@ -82,10 +82,12 @@
 	IJobManager manager = JobManagerFactory.make(threadContext);
         IOutputConnectionManager outputManager = OutputConnectionManagerFactory.make(threadContext);
 	IRepositoryConnectionManager connManager = RepositoryConnectionManagerFactory.make(threadContext);
+	INotificationConnectionManager notificationManager = NotificationConnectionManagerFactory.make(threadContext);
 	ITransformationConnectionManager transformationManager = TransformationConnectionManagerFactory.make(threadContext);
 
 	IOutputConnectorPool outputConnectorPool = OutputConnectorPoolFactory.make(threadContext);
 	IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
+	INotificationConnectorPool notificationConnectorPool = NotificationConnectorPoolFactory.make(threadContext);
 	ITransformationConnectorPool transformationConnectorPool = TransformationConnectorPoolFactory.make(threadContext);
 
 	String jobID = variableContext.getParameter("jobid");
@@ -204,6 +206,37 @@
 				</td>
 			</tr>
 			<tr>
+				<td class="description" colspan="1"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"viewjob.NotificationsColon")%></nobr></td>
+				<td class="boxcell" colspan="3">
+					<table class="formtable">
+						<tr class="formheaderrow">
+							<td class="formcolumnheader"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"viewjob.StageNumber")%></nobr></td>
+							<td class="formcolumnheader"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"viewjob.NotificationDescription")%></nobr></td>
+							<td class="formcolumnheader"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"viewjob.NotificationConnectionName")%></nobr></td>
+						</tr>
+<%
+		for (int j = 0; j < job.countNotifications(); j++)
+		{
+%>
+						<tr class="<%=((rowCounter++ % 2)==0)?"evenformrow":"oddformrow"%>">
+							<td class="formcolumncell"><%=(j+job.countPipelineStages()+2)%>.</td>
+							<td class="formcolumncell"><%=(job.getNotificationDescription(j)!=null)?org.apache.manifoldcf.ui.util.Encoder.bodyEscape(job.getNotificationDescription(j)):""%></td>
+							<td class="formcolumncell"><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(job.getNotificationConnectionName(j))%></td>
+						</tr>
+<%
+		}
+		if (job.countNotifications() == 0)
+		{
+%>
+						<tr class="formrow"><td class="formcolumnmessage" colspan="3"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"viewjob.NoNotificationConnections")%></td></tr>
+<%
+		}
+%>
+					</table>
+				</td>
+			</tr>
+
+			<tr>
 				<td class="separator" colspan="4"><hr/></td>
 			</tr>
 			<tr>
@@ -705,6 +738,39 @@
 			</tr>
 <%
 		}
+		
+		for (int j = 0; j < job.countNotifications(); j++)
+		{
+%>
+			<tr>
+				<td class="separator" colspan="4"><hr/></td>
+			</tr>
+			<tr>
+				<td class="message" colspan="4"><%=(j+job.countPipelineStages()+2)%>.</td>
+			</tr>
+			<tr>
+				<td colspan="4">
+<%
+			Specification os = job.getNotificationSpecification(j);
+			INotificationConnection thisConnection = notificationManager.load(job.getNotificationConnectionName(j));
+			INotificationConnector notificationConnector = notificationConnectorPool.grab(thisConnection);
+			if (notificationConnector != null)
+			{
+				try
+				{
+					notificationConnector.viewSpecification(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),os,1+job.countPipelineStages()+j);
+				}
+				finally
+				{
+					notificationConnectorPool.release(thisConnection,notificationConnector);
+				}
+			}
+%>
+				</td>
+			</tr>
+<%
+		}
+
 %>
 			<tr>
 				<td class="separator" colspan="4"><hr/></td>

Modified: manifoldcf/trunk/framework/example-common/connectors.xml
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/example-common/connectors.xml?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/example-common/connectors.xml (original)
+++ manifoldcf/trunk/framework/example-common/connectors.xml Tue Dec 23 14:46:43 2014
@@ -36,5 +36,7 @@
     <!-- Add your authority connectors here -->
     
     <!-- Add your repository connectors here -->
-    
+
+    <!-- Add your notification connectors here -->
+
 </connectors>

Modified: manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/CacheKeyFactory.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/CacheKeyFactory.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/CacheKeyFactory.java (original)
+++ manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/CacheKeyFactory.java Tue Dec 23 14:46:43 2014
@@ -63,6 +63,24 @@ public class CacheKeyFactory extends org
     return "REPOSITORYCONNECTION_"+connectionName;
   }
 
+  /** Construct a key which represents the general list of notification connectors.
+  *@return the cache key.
+  */
+  public static String makeNotificationConnectionsKey()
+  {
+    return "NOTIFICATIONCONNECTIONS";
+  }
+
+  /** Construct a key which represents an individual notification connection.
+  *@param connectionName is the name of the connector.
+  *@return the cache key.
+  */
+  public static String makeNotificationConnectionKey(String connectionName)
+  {
+    return "NOTIFICATIONCONNECTION_"+connectionName;
+  }
+
+
   /** Construct a key which represents the general list of jobs - for queries
   * that depend on the fixed kind of job data, not the dynamic data (e.g. status)
   *@return the cache key.

Modified: manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IJobDescription.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IJobDescription.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IJobDescription.java (original)
+++ manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IJobDescription.java Tue Dec 23 14:46:43 2014
@@ -141,6 +141,53 @@ public interface IJobDescription
   *@return the newly-created output specification.
   */
   public Specification insertPipelineStage(int index, boolean isOutput, String pipelineStageConnectionName, String pipelineStageDescription);
+
+  /** Clear notification connections.
+  */
+  public void clearNotifications();
+  
+  /** Add a notification.
+  *@param notificationConnectionName is the name of the notification connection to add.
+  *@param notificationDescription is a description of the notification being added.
+  *@return the empty specification for this notification.
+  */
+  public Specification addNotification(String notificationConnectionName, String notificationDescription);
+  
+  /** Get a count of pipeline connections.
+  *@return the current number of pipeline connections.
+  */
+  public int countNotifications();
+  
+  /** Get a specific notification connection name.
+  *@param index is the index of the notification whose connection name to get.
+  *@return the name of the connection.
+  */
+  public String getNotificationConnectionName(int index);
+
+  /** Get a specific notification description.
+  *@param index is the index of the notification whose description to get.
+  *@return the name of the connection.
+  */
+  public String getNotificationDescription(int index);
+
+  /** Get a specific notification specification.
+  *@param index is the index of the notification whose specification is needed.
+  *@return the specification for the connection.
+  */
+  public Specification getNotificationSpecification(int index);
+
+  /** Delete a notification.
+  *@param index is the index of the notification to delete.
+  */
+  public void deleteNotification(int index);
+  
+  /** Insert a new notification.
+  *@param index is the index to insert pipeline stage before
+  *@param notificationConnectionName is the connection name.
+  *@param notificationDescription is the description.
+  *@return the newly-created output specification.
+  */
+  public Specification insertNotification(int index, String notificationConnectionName, String notificationDescription);
   
   /** Set the job type.
   *@param type is the type (as an integer).

Modified: manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IJobManager.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IJobManager.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IJobManager.java (original)
+++ manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IJobManager.java Tue Dec 23 14:46:43 2014
@@ -118,6 +118,13 @@ public interface IJobManager
   public boolean checkIfReference(String connectionName)
     throws ManifoldCFException;
 
+  /** See if there's a reference to a notification connection name.
+  *@param connectionName is the name of the connection.
+  *@return true if there is a reference, false otherwise.
+  */
+  public boolean checkIfNotificationReference(String connectionName)
+    throws ManifoldCFException;
+
   /** See if there's a reference to an output connection name.
   *@param connectionName is the name of the connection.
   *@return true if there is a reference, false otherwise.
@@ -966,12 +973,35 @@ public interface IJobManager
   public void noteConnectorRegistration(String[] connectionNames)
     throws ManifoldCFException;
 
+  /**  Note the deregistration of a notification connector used by the specified connections.
+  * This method will be called when the connector is deregistered.  Jobs that use these connections
+  *  must therefore enter appropriate states.
+  *@param connectionNames is the set of connection names.
+  */
+  public void noteNotificationConnectorDeregistration(String[] connectionNames)
+    throws ManifoldCFException;
+
+  /** Note the registration of a notification connector used by the specified connections.
+  * This method will be called when a connector is registered, on which the specified
+  * connections depend.
+  *@param connectionNames is the set of connection names.
+  */
+  public void noteNotificationConnectorRegistration(String[] connectionNames)
+    throws ManifoldCFException;
+
   /** Note a change in connection configuration.
   * This method will be called whenever a connection's configuration is modified, or when an external repository change
   * is signalled.
   */
   public void noteConnectionChange(String connectionName)
     throws ManifoldCFException;
+
+  /** Note a change in notification connection configuration.
+  * This method will be called whenever a connection's configuration is modified, or when an external repository change
+  * is signalled.
+  */
+  public void noteNotificationConnectionChange(String connectionName)
+    throws ManifoldCFException;
     
   /**  Note the deregistration of an output connector used by the specified connections.
   * This method will be called when the connector is deregistered.  Jobs that use these connections

Modified: manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobDescription.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobDescription.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobDescription.java (original)
+++ manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobDescription.java Tue Dec 23 14:46:43 2014
@@ -44,6 +44,7 @@ public class JobDescription implements I
   protected String description = null;
   protected String connectionName = null;
   protected final List<PipelineStage> pipelineStages = new ArrayList<PipelineStage>();
+  protected final List<Notification> notifications = new ArrayList<Notification>();
   protected int type = TYPE_CONTINUOUS;
   protected int startMethod = START_WINDOWBEGIN;
   protected int priority = 5;
@@ -100,6 +101,12 @@ public class JobDescription implements I
         pipelineStage.getDescription(),
         pipelineStage.getSpecification().duplicate(readOnly)));
     }
+    for (Notification notification : notifications)
+    {
+      rval.notifications.add(new Notification(notification.getConnectionName(),
+        notification.getDescription(),
+        notification.getSpecification().duplicate(readOnly)));
+    }
     rval.description = description;
     rval.type = type;
     // No direct modification of this object is possible
@@ -135,6 +142,10 @@ public class JobDescription implements I
     {
       pipelineStage.getSpecification().makeReadOnly();
     }
+    for (Notification notification : notifications)
+    {
+      notification.getSpecification().makeReadOnly();
+    }
     documentSpecification.makeReadOnly();
   }
 
@@ -333,6 +344,8 @@ public class JobDescription implements I
   @Override
   public void deletePipelineStage(int index)
   {
+    if (readOnly)
+      throw new IllegalStateException("Attempt to change read-only object");
     PipelineStage ps = pipelineStages.remove(index);
     int stage = index;
     while (stage < pipelineStages.size())
@@ -342,6 +355,100 @@ public class JobDescription implements I
     }
   }
 
+  /** Clear notification connections.
+  */
+  @Override
+  public void clearNotifications()
+  {
+    if (readOnly)
+      throw new IllegalStateException("Attempt to change read-only object");
+    notifications.clear();
+  }
+  
+  /** Add a notification.
+  *@param notificationConnectionName is the name of the notification connection to add.
+  *@param notificationDescription is a description of the notification being added.
+  *@return the empty specification for this notification.
+  */
+  @Override
+  public Specification addNotification(String notificationConnectionName, String notificationDescription)
+  {
+    if (readOnly)
+      throw new IllegalStateException("Attempt to change read-only object");
+    Notification ps = new Notification(notificationConnectionName,notificationDescription);
+    notifications.add(ps);
+    return ps.getSpecification();
+  }
+  
+  /** Get a count of pipeline connections.
+  *@return the current number of pipeline connections.
+  */
+  @Override
+  public int countNotifications()
+  {
+    return notifications.size();
+  }
+  
+  /** Get a specific notification connection name.
+  *@param index is the index of the notification whose connection name to get.
+  *@return the name of the connection.
+  */
+  @Override
+  public String getNotificationConnectionName(int index)
+  {
+    return notifications.get(index).getConnectionName();
+  }
+
+  /** Get a specific notification description.
+  *@param index is the index of the notification whose description to get.
+  *@return the name of the connection.
+  */
+  @Override
+  public String getNotificationDescription(int index)
+  {
+    return notifications.get(index).getDescription();
+  }
+
+  /** Get a specific notification specification.
+  *@param index is the index of the notification whose specification is needed.
+  *@return the specification for the connection.
+  */
+  @Override
+  public Specification getNotificationSpecification(int index)
+  {
+    return notifications.get(index).getSpecification();
+  }
+
+  /** Delete a notification.
+  *@param index is the index of the notification to delete.
+  */
+  @Override
+  public void deleteNotification(int index)
+  {
+    if (readOnly)
+      throw new IllegalStateException("Attempt to change read-only object");
+    notifications.remove(index);
+  }
+  
+  /** Insert a new notification.
+  *@param index is the index to insert pipeline stage before
+  *@param notificationConnectionName is the connection name.
+  *@param notificationDescription is the description.
+  *@return the newly-created output specification.
+  */
+  @Override
+  public Specification insertNotification(int index, String notificationConnectionName, String notificationDescription)
+  {
+    if (readOnly)
+      throw new IllegalStateException("Attempt to change read-only object");
+    // What we do here depends on the kind of stage we're inserting.
+    // Both kinds take the current stage's prerequisite as their own.  But what happens to the current stage will
+    // differ as to whether its reference changes or not.
+    Notification ps = new Notification(notificationConnectionName,notificationDescription);
+    notifications.add(index,ps);
+    return ps.getSpecification();
+  }
+  
   /** Set the job type.
   *@param type is the type (as an integer).
   */
@@ -602,6 +709,43 @@ public class JobDescription implements I
     hopcountMode = mode;
   }
 
+  protected static class Notification
+  {
+    protected final String connectionName;
+    protected final String description;
+    protected final Specification specification;
+    
+    public Notification(String connectionName, String description)
+    {
+      this.connectionName = connectionName;
+      this.description = description;
+      this.specification = new Specification();
+    }
+
+    public Notification(String connectionName, String description, Specification spec)
+    {
+      this.connectionName = connectionName;
+      this.description = description;
+      this.specification = spec;
+    }
+
+    public Specification getSpecification()
+    {
+      return specification;
+    }
+    
+    public String getConnectionName()
+    {
+      return connectionName;
+    }
+    
+    public String getDescription()
+    {
+      return description;
+    }
+
+  }
+  
   protected static class PipelineStage
   {
     protected int prerequisiteStage;

Modified: manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobManager.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobManager.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobManager.java (original)
+++ manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobManager.java Tue Dec 23 14:46:43 2014
@@ -46,6 +46,7 @@ public class JobManager implements IJobM
   protected final IDBInterface database;
   protected final IOutputConnectionManager outputMgr;
   protected final IRepositoryConnectionManager connectionMgr;
+  protected final INotificationConnectionManager notificationMgr;
   protected final ITransformationConnectionManager transformationMgr;
   
   protected final IOutputConnectorManager outputConnectorMgr;
@@ -80,6 +81,7 @@ public class JobManager implements IJobM
     eventManager = new EventManager(database);
     outputMgr = OutputConnectionManagerFactory.make(threadContext);
     connectionMgr = RepositoryConnectionManagerFactory.make(threadContext);
+    notificationMgr = NotificationConnectionManagerFactory.make(threadContext);
     transformationMgr = TransformationConnectionManagerFactory.make(threadContext);
     outputConnectorMgr = OutputConnectorManagerFactory.make(threadContext);
     connectorMgr = ConnectorManagerFactory.make(threadContext);
@@ -96,7 +98,8 @@ public class JobManager implements IJobM
   {
     jobs.install(transformationMgr.getTableName(),transformationMgr.getConnectionNameColumn(),
       outputMgr.getTableName(),outputMgr.getConnectionNameColumn(),
-      connectionMgr.getTableName(),connectionMgr.getConnectionNameColumn());
+      connectionMgr.getTableName(),connectionMgr.getConnectionNameColumn(),
+      notificationMgr.getTableName(),notificationMgr.getConnectionNameColumn());
     jobQueue.install(jobs.getTableName(),jobs.idField);
     hopCount.install(jobs.getTableName(),jobs.idField);
     carryDown.install(jobs.getTableName(),jobs.idField);
@@ -388,6 +391,124 @@ public class JobManager implements IJobM
     }
   }
 
+  /**  Note the deregistration of a notification connector used by the specified connections.
+  * This method will be called when the connector is deregistered.  Jobs that use these connections
+  *  must therefore enter appropriate states.
+  *@param connectionNames is the set of connection names.
+  */
+  @Override
+  public void noteNotificationConnectorDeregistration(String[] connectionNames)
+    throws ManifoldCFException
+  {
+    // For each connection, find the corresponding list of jobs.  From these jobs, we want the job id and the status.
+    List<String> list = new ArrayList<String>();
+    int maxCount = database.findConjunctionClauseMax(new ClauseDescription[]{});
+    int currentCount = 0;
+    int i = 0;
+    while (i < connectionNames.length)
+    {
+      if (currentCount == maxCount)
+      {
+        noteNotificationConnectionDeregistration(list);
+        list.clear();
+        currentCount = 0;
+      }
+
+      list.add(connectionNames[i++]);
+      currentCount++;
+    }
+    if (currentCount > 0)
+      noteNotificationConnectionDeregistration(list);
+  }
+
+  /** Note deregistration for a batch of notification connection names.
+  */
+  protected void noteNotificationConnectionDeregistration(List<String> list)
+    throws ManifoldCFException
+  {
+    // Query for the matching jobs, and then for each job potentially adjust the state
+    Long[] jobIDs = jobs.findJobsMatchingNotifications(list);
+    if (jobIDs.length == 0)
+      return;
+
+    StringBuilder query = new StringBuilder();
+    ArrayList newList = new ArrayList();
+    
+    query.append("SELECT ").append(jobs.idField).append(",").append(jobs.statusField)
+      .append(" FROM ").append(jobs.getTableName()).append(" WHERE ")
+      .append(database.buildConjunctionClause(newList,new ClauseDescription[]{
+        new MultiClause(jobs.idField,jobIDs)}))
+      .append(" FOR UPDATE");
+    IResultSet set = database.performQuery(query.toString(),newList,null,null);
+    int i = 0;
+    while (i < set.getRowCount())
+    {
+      IResultRow row = set.getRow(i++);
+      Long jobID = (Long)row.getValue(jobs.idField);
+      int statusValue = jobs.stringToStatus((String)row.getValue(jobs.statusField));
+      jobs.noteNotificationConnectorDeregistration(jobID,statusValue);
+    }
+ }
+
+  /** Note the registration of a notification connector used by the specified connections.
+  * This method will be called when a connector is registered, on which the specified
+  * connections depend.
+  *@param connectionNames is the set of connection names.
+  */
+  @Override
+  public void noteNotificationConnectorRegistration(String[] connectionNames)
+    throws ManifoldCFException
+  {
+    // For each connection, find the corresponding list of jobs.  From these jobs, we want the job id and the status.
+    List<String> list = new ArrayList<String>();
+    int maxCount = database.findConjunctionClauseMax(new ClauseDescription[]{});
+    int currentCount = 0;
+    int i = 0;
+    while (i < connectionNames.length)
+    {
+      if (currentCount == maxCount)
+      {
+        noteNotificationConnectionRegistration(list);
+        list.clear();
+        currentCount = 0;
+      }
+
+      list.add(connectionNames[i++]);
+      currentCount++;
+    }
+    if (currentCount > 0)
+      noteNotificationConnectionRegistration(list);
+  }
+
+  /** Note registration for a batch of connection names.
+  */
+  protected void noteNotificationConnectionRegistration(List<String> list)
+    throws ManifoldCFException
+  {
+    // Query for the matching jobs, and then for each job potentially adjust the state
+    Long[] jobIDs = jobs.findJobsMatchingNotifications(list);
+    if (jobIDs.length == 0)
+      return;
+
+    StringBuilder query = new StringBuilder();
+    ArrayList newList = new ArrayList();
+    
+    query.append("SELECT ").append(jobs.idField).append(",").append(jobs.statusField)
+      .append(" FROM ").append(jobs.getTableName()).append(" WHERE ")
+      .append(database.buildConjunctionClause(newList,new ClauseDescription[]{
+        new MultiClause(jobs.idField,jobIDs)}))
+      .append(" FOR UPDATE");
+    IResultSet set = database.performQuery(query.toString(),newList,null,null);
+    int i = 0;
+    while (i < set.getRowCount())
+    {
+      IResultRow row = set.getRow(i++);
+      Long jobID = (Long)row.getValue(jobs.idField);
+      int statusValue = jobs.stringToStatus((String)row.getValue(jobs.statusField));
+      jobs.noteNotificationConnectorDeregistration(jobID,statusValue);
+    }
+  }
+
   /**  Note the deregistration of an output connector used by the specified connections.
   * This method will be called when the connector is deregistered.  Jobs that use these connections
   *  must therefore enter appropriate states.
@@ -635,6 +756,17 @@ public class JobManager implements IJobM
     jobs.noteConnectionChange(connectionName);
   }
 
+  /** Note a change in notification connection configuration.
+  * This method will be called whenever a notification connection's configuration is modified, or when an external repository change
+  * is signalled.
+  */
+  @Override
+  public void noteNotificationConnectionChange(String connectionName)
+    throws ManifoldCFException
+  {
+    jobs.noteConnectionChange(connectionName);
+  }
+
   /** Note a change in output connection configuration.
   * This method will be called whenever a connection's configuration is modified, or when an external target config change
   * is signalled.
@@ -828,6 +960,17 @@ public class JobManager implements IJobM
     return jobs.checkIfReference(connectionName);
   }
 
+  /** See if there's a reference to a notification connection name.
+  *@param connectionName is the name of the connection.
+  *@return true if there is a reference, false otherwise.
+  */
+  @Override
+  public boolean checkIfNotificationReference(String connectionName)
+    throws ManifoldCFException
+  {
+    return jobs.checkIfNotificationReference(connectionName);
+  }
+
   /** See if there's a reference to an output connection name.
   *@param connectionName is the name of the connection.
   *@return true if there is a reference, false otherwise.

Modified: manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/Jobs.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/Jobs.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/Jobs.java (original)
+++ manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/Jobs.java Tue Dec 23 14:46:43 2014
@@ -345,6 +345,7 @@ public class Jobs extends org.apache.man
   protected final ScheduleManager scheduleManager;
   protected final HopFilterManager hopFilterManager;
   protected final PipelineManager pipelineManager;
+  protected final NotificationManager notificationManager;
   
   protected final IOutputConnectionManager outputMgr;
   protected final IRepositoryConnectionManager connectionMgr;
@@ -366,6 +367,7 @@ public class Jobs extends org.apache.man
     scheduleManager = new ScheduleManager(threadContext,database);
     hopFilterManager = new HopFilterManager(threadContext,database);
     pipelineManager = new PipelineManager(threadContext,database);
+    notificationManager = new NotificationManager(threadContext,database);
     
     cacheManager = CacheManagerFactory.make(threadContext);
     lockManager = LockManagerFactory.make(threadContext);
@@ -379,7 +381,8 @@ public class Jobs extends org.apache.man
   */
   public void install(String transTableName, String transNameField,
     String outputTableName, String outputNameField,
-    String connectionTableName, String connectionNameField)
+    String connectionTableName, String connectionNameField,
+    String notificationConnectionTableName, String notificationConnectionNameField)
     throws ManifoldCFException
   {
     // Standard practice: Have a loop around everything, in case upgrade needs it.
@@ -442,6 +445,7 @@ public class Jobs extends org.apache.man
           pipelineManager.writeOutputStage(id,outputConnectionName,outputConnectionSpec);
         }
       }
+      notificationManager.install(getTableName(),idField,notificationConnectionTableName,notificationConnectionNameField);
       scheduleManager.install(getTableName(),idField);
       hopFilterManager.install(getTableName(),idField);
 
@@ -497,6 +501,7 @@ public class Jobs extends org.apache.man
     {
       hopFilterManager.deinstall();
       scheduleManager.deinstall();
+      notificationManager.deinstall();
       pipelineManager.deinstall();
       performDrop(null);
     }
@@ -534,6 +539,27 @@ public class Jobs extends org.apache.man
     analyzeTable();
   }
 
+  /** Find a list of jobs matching specified notification names.
+  */
+  public Long[] findJobsMatchingNotifications(List<String> notificationConnectionNames)
+    throws ManifoldCFException
+  {
+    StringBuilder query = new StringBuilder();
+    ArrayList params = new ArrayList();
+    query.append("SELECT ").append(idField)
+      .append(" FROM ").append(getTableName()).append(" t1 WHERE EXISTS(");
+    notificationManager.buildNotificationQueryClause(query,params,"t1."+idField,notificationConnectionNames);
+    query.append(")");
+    IResultSet set = performQuery(query.toString(),params,null,null);
+    Long[] rval = new Long[set.getRowCount()];
+    for (int i = 0; i < rval.length; i++)
+    {
+      IResultRow row = set.getRow(i);
+      rval[i] = (Long)row.getValue(idField);
+    }
+    return rval;
+  }
+
   /** Find a list of jobs matching specified transformation names.
   */
   public Long[] findJobsMatchingTransformations(List<String> transformationConnectionNames)
@@ -780,6 +806,7 @@ public class Jobs extends org.apache.man
         scheduleManager.deleteRows(id);
         hopFilterManager.deleteRows(id);
         pipelineManager.deleteRows(id);
+        notificationManager.deleteRows(id);
         ArrayList params = new ArrayList();
         String query = buildConjunctionClause(params,new ClauseDescription[]{
           new UnitaryClause(idField,id)});
@@ -933,6 +960,14 @@ public class Jobs extends org.apache.man
                     values.put(assessmentStateField,assessmentStateToString(ASSESSMENT_UNKNOWN));
                 }
 
+                // Changing notifications should never reset seeding.
+                /*
+                if (isSame)
+                {
+                  isSame = notificationManager.compareRows(id,jobDescription);
+                }
+                */
+                
                 if (isSame)
                 {
                   String oldDocSpecXML = (String)row.getValue(documentSpecField);
@@ -951,6 +986,7 @@ public class Jobs extends org.apache.man
                   new UnitaryClause(idField,id)});
                 performUpdate(values," WHERE "+query,params,null);
                 pipelineManager.deleteRows(id);
+                notificationManager.deleteRows(id);
                 scheduleManager.deleteRows(id);
                 hopFilterManager.deleteRows(id);
               }
@@ -968,6 +1004,8 @@ public class Jobs extends org.apache.man
 
               // Write pipeline rows
               pipelineManager.writeRows(id,jobDescription);
+              // Write notification rows
+              notificationManager.writeRows(id,jobDescription);
               // Write schedule records
               scheduleManager.writeRows(id,jobDescription);
               // Write hop filter rows
@@ -1476,6 +1514,16 @@ public class Jobs extends org.apache.man
     invalidateCurrentUnregisteredState(jobID,oldStatusValue);
   }
   
+  /** Signal to a job that its underlying notification connector has gone away.
+  *@param jobID is the identifier of the job.
+  *@param oldStatusValue is the current status value for the job.
+  */
+  public void noteNotificationConnectorDeregistration(Long jobID, int oldStatusValue)
+    throws ManifoldCFException
+  {
+    // MHL
+  }
+  
   /** Signal to a job that its underlying connector has gone away.
   *@param jobID is the identifier of the job.
   *@param oldStatusValue is the current status value for the job.
@@ -1516,6 +1564,16 @@ public class Jobs extends org.apache.man
     performUpdate(newValues,"WHERE "+query,list,invKey);
   }
   
+  /** Signal to a job that its underlying notification connector has returned.
+  *@param jobID is the identifier of the job.
+  *@param oldStatusValue is the current status value for the job.
+  */
+  public void noteNotificationConnectorRegistration(Long jobID, int oldStatusValue)
+    throws ManifoldCFException
+  {
+    // MHL
+  }
+
   /** Signal to a job that its underlying connector has returned.
   *@param jobID is the identifier of the job.
   *@param oldStatusValue is the current status value for the job.
@@ -1542,6 +1600,16 @@ public class Jobs extends org.apache.man
     performUpdate(newValues,"WHERE "+query,list,null);
   }
 
+  /** Note a change in notification connection configuration.
+  * This method will be called whenever a notification connection's configuration is modified, or when an external repository change
+  * is signalled.
+  */
+  public void noteNotificationConnectionChange(String connectionName)
+    throws ManifoldCFException
+  {
+    // Notification configuration change does not change anything in a crawl
+  }
+
   /** Note a change in output connection configuration.
   * This method will be called whenever a connection's configuration is modified, or when an external target config change
   * is signalled.
@@ -2962,6 +3030,21 @@ public class Jobs extends org.apache.man
     return set.getRowCount() > 0;
   }
 
+  /** See if there's a reference to a notification connection name.
+  *@param connectionName is the name of the connection.
+  *@return true if there is a reference, false otherwise.
+  */
+  public boolean checkIfNotificationReference(String connectionName)
+    throws ManifoldCFException
+  {
+    ArrayList list = new ArrayList();
+    String query = buildConjunctionClause(list,new ClauseDescription[]{
+      new UnitaryClause(notificationManager.notificationNameField,connectionName)});
+    IResultSet set = performQuery("SELECT "+notificationManager.ownerIDField+" FROM "+notificationManager.getTableName()+
+      " WHERE "+query,list,new StringSet(getJobsKey()),null);
+    return set.getRowCount() > 0;
+  }
+
   /** See if there's a reference to an output connection name.
   *@param connectionName is the name of the connection.
   *@return true if there is a reference, false otherwise.
@@ -3519,6 +3602,7 @@ public class Jobs extends org.apache.man
 
       // Fill in schedules for jobs
       pipelineManager.getRows(returnValues,idList,params);
+      notificationManager.getRows(returnValues,idList,params);
       scheduleManager.getRows(returnValues,idList,params);
       hopFilterManager.getRows(returnValues,idList,params);
     }

Modified: manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/CrawlerAgent.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/CrawlerAgent.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/CrawlerAgent.java (original)
+++ manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/CrawlerAgent.java Tue Dec 23 14:46:43 2014
@@ -784,6 +784,7 @@ public class CrawlerAgent implements IAg
 
     // Threads are down; release connectors
     RepositoryConnectorPoolFactory.make(threadContext).flushUnusedConnectors();
+    NotificationConnectorPoolFactory.make(threadContext).flushUnusedConnectors();
     numWorkerThreads = 0;
     numDeleteThreads = 0;
     numExpireThreads = 0;

Modified: manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/IdleCleanupThread.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/IdleCleanupThread.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/IdleCleanupThread.java (original)
+++ manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/IdleCleanupThread.java Tue Dec 23 14:46:43 2014
@@ -56,6 +56,7 @@ public class IdleCleanupThread extends T
       IThreadContext threadContext = ThreadContextFactory.make();
       
       IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
+      INotificationConnectorPool notificationConnectorPool = NotificationConnectorPoolFactory.make(threadContext);
       
       // Loop
       while (true)
@@ -65,6 +66,7 @@ public class IdleCleanupThread extends T
         {
           // Do the cleanup
           repositoryConnectorPool.pollAllConnectors();
+          notificationConnectorPool.pollAllConnectors();
           // This is unnecessary because agents.interfaces.IdleCleanupThread does it.
           //ManifoldCF.pollAll(threadContext);
           

Modified: manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/JobNotificationThread.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/JobNotificationThread.java?rev=1647585&r1=1647584&r2=1647585&view=diff
==============================================================================
--- manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/JobNotificationThread.java (original)
+++ manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/JobNotificationThread.java Tue Dec 23 14:46:43 2014
@@ -72,15 +72,14 @@ public class JobNotificationThread exten
           // Before we begin, conditionally reset
           resetManager.waitForReset(threadContext);
 
+          // Find the jobs ready for inactivity and notify them
           JobNotifyRecord[] jobsNeedingNotification = jobManager.getJobsReadyForInactivity(processID);
           try
           {
             Set<OutputAndRepositoryConnection> connectionNames = new HashSet<OutputAndRepositoryConnection>();
             
-            int k = 0;
-            while (k < jobsNeedingNotification.length)
+            for (JobNotifyRecord jsr : jobsNeedingNotification)
             {
-              JobNotifyRecord jsr = jobsNeedingNotification[k++];
               Long jobID = jsr.getJobID();
               IJobDescription job = jobManager.load(jobID,true);
               if (job != null)
@@ -147,10 +146,8 @@ public class JobNotificationThread exten
             }
             
             // Go through jobs again, and put the notified ones into the inactive state.
-            k = 0;
-            while (k < jobsNeedingNotification.length)
+            for (JobNotifyRecord jsr : jobsNeedingNotification)
             {
-              JobNotifyRecord jsr = jobsNeedingNotification[k++];
               Long jobID = jsr.getJobID();
               IJobDescription job = jobManager.load(jobID,true);
               if (job != null)
@@ -249,16 +246,14 @@ public class JobNotificationThread exten
               throw exception;
           }
 
-          // ???
+          // We also need to do a notify for jobs that are about to be deleted
           JobNotifyRecord[] jobsNeedingDeleteNotification = jobManager.getJobsReadyForDelete(processID);
           try
           {
             Set<OutputAndRepositoryConnection> connectionNames = new HashSet<OutputAndRepositoryConnection>();
             
-            int k = 0;
-            while (k < jobsNeedingDeleteNotification.length)
+            for (JobNotifyRecord jsr : jobsNeedingDeleteNotification)
             {
-              JobNotifyRecord jsr = jobsNeedingDeleteNotification[k++];
               Long jobID = jsr.getJobID();
               IJobDescription job = jobManager.load(jobID,true);
               if (job != null)
@@ -325,10 +320,8 @@ public class JobNotificationThread exten
             }
             
             // Go through jobs again, and put the notified ones into the inactive state.
-            k = 0;
-            while (k < jobsNeedingDeleteNotification.length)
+            for (JobNotifyRecord jsr : jobsNeedingDeleteNotification)
             {
-              JobNotifyRecord jsr = jobsNeedingDeleteNotification[k++];
               Long jobID = jsr.getJobID();
               IJobDescription job = jobManager.load(jobID,true);
               if (job != null)



Mime
View raw message