You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@manifoldcf.apache.org by kw...@apache.org on 2014/06/10 01:19:10 UTC

svn commit: r1601529 [3/6] - in /manifoldcf/trunk: ./ connectors/ connectors/nulltransformation/ framework/agents/src/main/java/org/apache/manifoldcf/agents/ framework/agents/src/main/java/org/apache/manifoldcf/agents/incrementalingest/ framework/agent...

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=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editjob.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editjob.jsp Mon Jun  9 23:19:08 2014
@@ -35,15 +35,30 @@
 	IRepositoryConnection[] connList = connMgr.getAllConnections();
 	IOutputConnectionManager outputMgr = OutputConnectionManagerFactory.make(threadContext);
 	IOutputConnection[] outputList = outputMgr.getAllConnections();
+	ITransformationConnectionManager transformationMgr = TransformationConnectionManagerFactory.make(threadContext);
+	ITransformationConnection[] transformationList = transformationMgr.getAllConnections();
 
 	IOutputConnectorPool outputConnectorPool = OutputConnectorPoolFactory.make(threadContext);
 	IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
+	ITransformationConnectorPool transformationConnectorPool = TransformationConnectorPoolFactory.make(threadContext);
 
-	// Figure out tab name
+	// Figure out tab name and sequence number
 	String tabName = variableContext.getParameter("tabname");
+	String tabSequenceNumber = variableContext.getParameter("sequencenumber");
+	int tabSequenceInt;
 	if (tabName == null || tabName.length() == 0)
+	{
 		tabName = Messages.getString(pageContext.getRequest().getLocale(),"editjob.Name");
-
+		tabSequenceInt = -1;
+	}
+	else
+	{
+		if (tabSequenceNumber == null || tabSequenceNumber.length() == 0)
+			tabSequenceInt = -1;
+		else
+			tabSequenceInt = Integer.parseInt(tabSequenceNumber);
+	}
+	
 	// Get a loaded job object, somehow.
 	String jobID = null;
 	IJobDescription job = (IJobDescription)threadContext.get("JobObject");
@@ -64,10 +79,13 @@
 	// Setup default fields
 	String connectionName = "";
 	String outputName = "";
+	String[] transformationNames = new String[0];
+	String[] transformationDescriptions = new String[0];
 	String description = "";
 	int type = IJobDescription.TYPE_SPECIFIED;
 	OutputSpecification outputSpecification = new OutputSpecification();
 	DocumentSpecification documentSpecification = new DocumentSpecification();
+	OutputSpecification[] transformationSpecifications = new OutputSpecification[0];
 	ArrayList scheduleRecords = new ArrayList();
 
 	EnumeratedValues dayOfWeek = null;
@@ -107,16 +125,24 @@
 		description = job.getDescription();
 		outputName = job.getOutputConnectionName();
 		connectionName = job.getConnectionName();
+		transformationNames = new String[job.countPipelineStages()];
+		transformationDescriptions = new String[job.countPipelineStages()];
+		transformationSpecifications = new OutputSpecification[job.countPipelineStages()];
+		for (int j = 0; j < job.countPipelineStages(); j++)
+		{
+			transformationNames[j] = job.getPipelineStageConnectionName(j);
+			transformationDescriptions[j] = job.getPipelineStageDescription(j);
+			transformationSpecifications[j] = job.getPipelineStageSpecification(j);
+		}
 		type = job.getType();
 		startMethod = job.getStartMethod();
 		hopcountMode = job.getHopcountMode();
 		outputSpecification = job.getOutputSpecification();
 		documentSpecification = job.getSpecification();
 		// Fill in schedule records from job
-		int j = 0;
-		while (j < job.getScheduleRecordCount())
+		for (int j = 0; j < job.getScheduleRecordCount(); j++)
 		{
-			scheduleRecords.add(job.getScheduleRecord(j++));
+			scheduleRecords.add(job.getScheduleRecord(j));
 		}
 
 		priority = job.getPriority();
@@ -143,7 +169,8 @@
 
 	int model = IRepositoryConnector.MODEL_ADD_CHANGE_DELETE;
 	String[] relationshipTypes = null;
-	ArrayList tabsArray = new ArrayList();
+	List<String> tabsArray = new ArrayList<String>();
+	List<Integer> sequenceArray = new ArrayList<Integer>();
 	
 	IRepositoryConnection connection = null;
 	IOutputConnection outputConnection = null;
@@ -157,22 +184,78 @@
 	{
 		outputConnection = outputMgr.load(outputName);
 	}
+	ITransformationConnection[] transformationConnections = new ITransformationConnection[transformationNames.length];
+	for (int j = 0; j < transformationConnections.length; j++)
+	{
+		transformationConnections[j] = transformationMgr.load(transformationNames[j]);
+	}
 
 	// Set up the predefined tabs
 	tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editjob.Name"));
+	sequenceArray.add(null);
 	tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editjob.Connection"));
+	sequenceArray.add(null);
 	if (connectionName.length() > 0)
 	{
 		tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editjob.Scheduling"));
+		sequenceArray.add(null);
 		if (relationshipTypes != null && relationshipTypes.length > 0)
+		{
 			tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editjob.HopFilters"));
+			sequenceArray.add(null);
+		}
 		tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editjob.ForcedMetadata"));
+		sequenceArray.add(null);
+	}
+
+	// Get the names of the various Javascript methods we'll need to call
+	String outputCheckMethod = "checkOutputSpecification";
+	String outputSaveCheckMethod = "checkOutputSpecificationForSave";
+	String checkMethod = "checkSpecification";
+	String saveCheckMethod = "checkSpecificationForSave";
+	String[] transformationCheckMethods = new String[transformationConnections.length];
+	String[] transformationCheckForSaveMethods = new String[transformationConnections.length];
+	for (int j = 0; j < transformationConnections.length; j++)
+	{
+		transformationCheckMethods[j] = "unknown";
+		transformationCheckForSaveMethods[j] = "unknown";
+	}
+	
+	if (outputConnection != null)
+	{
+		IOutputConnector outputConnector = OutputConnectorFactory.getConnectorNoCheck(outputConnection.getClassName());
+		if (outputConnector != null)
+		{
+			outputCheckMethod = outputConnector.getFormCheckJavascriptMethodName(1+transformationNames.length);
+			outputSaveCheckMethod = outputConnector.getFormPresaveCheckJavascriptMethodName(1+transformationNames.length);
+		}
 	}
 
+	if (connection != null)
+	{
+		IRepositoryConnector connector = RepositoryConnectorFactory.getConnectorNoCheck(connection.getClassName());
+		if (connector != null)
+		{
+			checkMethod = connector.getFormCheckJavascriptMethodName(0);
+			saveCheckMethod = connector.getFormPresaveCheckJavascriptMethodName(0);
+		}
+	}
+
+	for (int j = 0; j < transformationConnections.length; j++)
+	{
+		ITransformationConnector transformationConnector = TransformationConnectorFactory.getConnectorNoCheck(transformationConnections[j].getClassName());
+		if (transformationConnector != null)
+		{
+			transformationCheckMethods[j] = transformationConnector.getFormCheckJavascriptMethodName(1+j);
+			transformationCheckForSaveMethods[j] = transformationConnector.getFormPresaveCheckJavascriptMethodName(1+j);
+		}
+	}
 
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
@@ -191,6 +274,18 @@
 		if (checkForm())
 		{
 			document.editjob.tabname.value = newtab;
+			document.editjob.sequencenumber.value = "";
+			document.editjob.submit();
+		}
+	}
+
+	// Use this method to repost the form and pick a new tab
+	function SelectSequencedTab(newtab, sequencenumber)
+	{
+		if (checkForm())
+		{
+			document.editjob.tabname.value = newtab;
+			document.editjob.sequencenumber.value = sequencenumber;
 			document.editjob.submit();
 		}
 	}
@@ -241,14 +336,26 @@
 				document.editjob.description.focus();
 				return;
 			}
-			if (window.checkOutputSpecificationForSave)
+			if (window.<%=outputSaveCheckMethod%>)
 			{
-				if (checkOutputSpecificationForSave() == false)
+				if (<%=outputSaveCheckMethod%>() == false)
 					return;
 			}
-			if (window.checkSpecificationForSave)
+<%
+	for (int j = 0; j < transformationCheckForSaveMethods.length; j++)
+	{
+%>
+			if (window.<%=transformationCheckForSaveMethods[j]%>)
 			{
-				if (checkSpecificationForSave() == false)
+				if (<%=transformationCheckForSaveMethods[j]%>() == false)
+					return;
+			}
+<%
+	}
+%>
+			if (window.<%=saveCheckMethod%>)
+			{
+				if (<%=saveCheckMethod%>() == false)
 					return;
 			}
 			document.editjob.op.value="Save";
@@ -268,6 +375,39 @@
 		postFormNew();
 	}
 
+	function InsertPipelineStage(n)
+	{
+		if (editjob.pipeline_connectionname.value == "")
+		{
+			alert("<%=Messages.getBodyJavascriptString(pageContext.getRequest().getLocale(),"editjob.SelectAPipelineStageConnectionName")%>");
+			editjob.pipeline_connectionname.focus();
+			return;
+		}
+		eval("document.editjob.pipeline_"+n+"_op.value = 'Insert'");
+		postFormSetAnchor("pipeline_"+(n+1)+"_tag");
+	}
+
+	function AppendPipelineStage()
+	{
+		if (editjob.pipeline_connectionname.value == "")
+		{
+			alert("<%=Messages.getBodyJavascriptString(pageContext.getRequest().getLocale(),"editjob.SelectAPipelineStageConnectionName")%>");
+			editjob.pipeline_connectionname.focus();
+			return;
+		}
+		document.editjob.pipeline_op.value="Add";
+		postFormSetAnchor("pipeline_tag");
+	}
+	
+	function DeletePipelineStage(n)
+	{
+		eval("document.editjob.pipeline_"+n+"_op.value = 'Delete'");
+		if (n == 0)
+			postFormSetAnchor("pipeline_tag");
+		else
+			postFormSetAnchor("pipeline_"+(n-1)+"_tag");
+	}
+	
 	function AddScheduledTime()
 	{
 		if (editjob.duration.value != "" && !isInteger(editjob.duration.value))
@@ -325,15 +465,27 @@
 		if (!checkSchedule())
 			return false;
 		// Check the output connector part
-		if (window.checkOutputSpecification)
+		if (window.<%=outputCheckMethod%>)
+		{
+			if (<%=outputCheckMethod%>() == false)
+				return false;
+		}
+<%
+	for (int j = 0; j < transformationCheckMethods.length; j++)
+	{
+%>
+		if (window.<%=transformationCheckMethods[j]%>)
 		{
-			if (checkOutputSpecification() == false)
+			if (<%=transformationCheckMethods[j]%>() == false)
 				return false;
 		}
+<%
+	}
+%>
 		// Check the connector part
-		if (window.checkSpecification)
+		if (window.<%=checkMethod%>)
 		{
-			if (checkSpecification() == false)
+			if (<%=checkMethod%>() == false)
 				return false;
 		}
 		return true;
@@ -442,13 +594,18 @@
 		{
 			try
 			{
-				outputConnector.outputSpecificationHeader(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),outputSpecification,tabsArray);
+				outputConnector.outputSpecificationHeader(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),outputSpecification,1,tabsArray);
 			}
 			finally
 			{
 				outputConnectorPool.release(outputConnection,outputConnector);
 			}
 		}
+		Integer outputConnectionSequenceNumber = new Integer(1+transformationConnections.length);
+		while (sequenceArray.size() < tabsArray.size())
+		{
+			sequenceArray.add(outputConnectionSequenceNumber);
+		}
 	}
 %>
 
@@ -460,14 +617,43 @@
 		{
 			try
 			{
-				repositoryConnector.outputSpecificationHeader(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),documentSpecification,tabsArray);
+				repositoryConnector.outputSpecificationHeader(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),documentSpecification,0,tabsArray);
 			}
 			finally
 			{
 				repositoryConnectorPool.release(connection,repositoryConnector);
 			}
 		}
+		Integer repositoryConnectionSequenceNumber = new Integer(0);
+		while (sequenceArray.size() < tabsArray.size())
+		{
+			sequenceArray.add(repositoryConnectionSequenceNumber);
+		}
+	}
+%>
+
+<%
+	for (int j = 0; j < transformationConnections.length; j++)
+	{
+		ITransformationConnector transformationConnector = transformationConnectorPool.grab(transformationConnections[j]);
+		if (transformationConnector != null)
+		{
+			try
+			{
+				transformationConnector.outputSpecificationHeader(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),transformationSpecifications[j],1+j,tabsArray);
+			}
+			finally
+			{
+				transformationConnectorPool.release(transformationConnections[j],transformationConnector);
+			}
+		}
+		Integer transformationConnectionSequenceNumber = new Integer(1+j);
+		while (sequenceArray.size() < tabsArray.size())
+		{
+			sequenceArray.add(transformationConnectionSequenceNumber);
+		}
 	}
+	
 %>
 
 </head>
@@ -501,6 +687,7 @@
 	  <input type="hidden" name="type" value="job"/>
 	  <input type="hidden" name="index" value=""/>
 	  <input type="hidden" name="tabname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(tabName)%>'/>
+	  <input type="hidden" name="sequencenumber" value='<%=((tabSequenceInt==-1)?"":Integer.toString(tabSequenceInt))%>'/>
 <%
 	if (jobID != null)
 	{
@@ -510,42 +697,100 @@
 	}
 %>
 	    <table class="tabtable">
-	      <tr class="tabrow">
+	      <tr class="tabspacerrow">
+		<td class="spacertab" colspan="<%=tabsArray.size()%>"></td>
+		<td class="remaindertab" rowspan="3">
 <%
-	int tabNum = 0;
-	while (tabNum < tabsArray.size())
+	if (description.length() > 0)
 	{
-		String tab = (String)tabsArray.get(tabNum++);
-		if (tab.equals(tabName))
+%>
+			  <nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.EditJob")%> '<%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(description)%>'</nobr>
+<%
+	}
+	else
+	{
+%>
+		          <nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.EditaJob")%></nobr>
+<%
+	}
+%>
+		</td>
+	      </tr>
+	      <tr class="tabsequencerow">
+<%
+	Integer currentSequenceNumber = null;
+	int startColumn = 0;
+	for (int tabNum = 0; tabNum < tabsArray.size(); tabNum++)
+	{
+		boolean doswitch = false;
+		Integer sequenceNumber = sequenceArray.get(tabNum);
+		if (sequenceNumber == null || currentSequenceNumber == null)
+			doswitch = (sequenceNumber != null || currentSequenceNumber != null);
+		else
+			doswitch = !sequenceNumber.equals(currentSequenceNumber);
+		if (doswitch)
 		{
+			int colspan = tabNum - startColumn;
+			if (colspan > 0)
+			{
+				if (currentSequenceNumber == null)
+				{
 %>
-		      <td class="activetab"><nobr><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(tab)%></nobr></td>
+		      <td class="blanksequencetab" colspan="<%=colspan%>"></td>
+<%
+				}
+				else
+				{
+%>
+		      <td class="sequencetab" colspan="<%=colspan%>"><%=(currentSequenceNumber.intValue()+1)%>.</td>
+<%
+				}
+			}
+			startColumn = tabNum;
+			currentSequenceNumber = sequenceNumber;
+		}
+	}
+	if (startColumn != tabsArray.size())
+	{
+		int colspan = tabsArray.size() - startColumn;
+		if (currentSequenceNumber == null)
+		{
+%>
+		      <td class="blanksequencetab" colspan="<%=colspan%>"></td>
 <%
 		}
 		else
 		{
 %>
-		      <td class="passivetab"><nobr><a href="javascript:void(0);" alt='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(tab)+" "+Messages.getAttributeString(pageContext.getRequest().getLocale(),"editjob.tab")%>' onclick='<%="javascript:SelectTab(\""+tab+"\");return false;"%>'><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(tab)%></a></nobr></td>
+		      <td class="sequencetab" colspan="<%=colspan%>"><%=(currentSequenceNumber.intValue()+1)%>.</td>
 <%
 		}
 	}
+	// Final (remainder) cell left out on purpose; filled in above.
 %>
-		      <td class="remaindertab">
+	      </tr>
+	      <tr class="tabrow">
 <%
-	if (description.length() > 0)
+	for (int tabNum = 0; tabNum < tabsArray.size(); tabNum++)
 	{
+		String tab = tabsArray.get(tabNum);
+		Integer sequenceNumber = sequenceArray.get(tabNum);
+		int sequenceNumberInt = (sequenceNumber == null)?-1:sequenceNumber.intValue();
+		if (tab.equals(tabName) && (tabSequenceInt == -1 || sequenceNumberInt == tabSequenceInt))
+		{
 %>
-			  <nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.EditJob")%> '<%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(description)%>'</nobr>
+		      <td class="activetab"><nobr><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(tab)%></nobr></td>
 <%
-	}
-	else
-	{
+		}
+		else
+		{
 %>
-		          <nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.EditaJob")%></nobr>
+		      <td class="passivetab"><nobr><a href="javascript:void(0);" alt='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(tab)+" "+Messages.getAttributeString(pageContext.getRequest().getLocale(),"editjob.tab")%>' onclick='<%="javascript:SelectSequencedTab(\""+tab+"\",\""+((sequenceNumber==null)?"":sequenceNumber.toString())+"\");return false;"%>'><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(tab)%></a></nobr></td>
 <%
+		}
 	}
+	// Missing remainder tab ON PURPOSE -- comes from rowspan=2 tab above
 %>
-		      </td>
 	      </tr>
 	      <tr class="tabbodyrow">
 		<td class="tabbody" colspan='<%=Integer.toString(tabsArray.size()+1)%>'>
@@ -553,7 +798,7 @@
 		  <input type="hidden" name="schedulerecords" value='<%=Integer.toString(scheduleRecords.size())%>'/>
 <%
 	// The NAME tab
-	if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.Name")))
+	if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.Name")) && tabSequenceInt == -1)
 	{
 %>
 		  <table class="displaytable">
@@ -576,7 +821,7 @@
 	}
 
 	// Forced Metadata tab
-	if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.ForcedMetadata")))
+	if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.ForcedMetadata")) && tabSequenceInt == -1)
 	{
 %>
 		  <table class="displaytable">
@@ -685,7 +930,7 @@
 	}
 	
 	// Hop Filters tab
-	if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.HopFilters")))
+	if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.HopFilters")) && tabSequenceInt == -1)
 	{
 	    if (relationshipTypes != null)
 	    {
@@ -750,76 +995,159 @@
 	}
 
 	// Connection tab
-	if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.Connection")))
+	if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.Connection")) && tabSequenceInt == -1)
 	{
+		int displaySequence = 0;
+
 %>
 		  <table class="displaytable">
+			<tr><td class="separator" colspan="4"><hr/></td></tr>
 			<tr>
-				<td class="separator" colspan="4"><hr/></td>
-			</tr>
-			<tr>
+				<td colspan="1" class="description"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.PipelineColon")%></nobr></td>
+				<td class="boxcell" colspan="3">
+					<table class="formtable">
+						<tr class="formheaderrow">
+							<td class="formcolumnheader">
+								<input name="pipeline_count" type="hidden" value="<%=transformationNames.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.StageDescription")%></nobr></td>
+							<td class="formcolumnheader"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.StageConnectionName")%></nobr></td>
+						</tr>
+						<tr class="<%=((displaySequence % 2)==0)?"evenformrow":"oddformrow"%>">
+							<td class="formcolumncell"></td>
+							<td class="formcolumncell"><%=(++displaySequence)%>.</td>
+							<td class="formcolumncell"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.RepositoryStage")%></td>
+							<td class="formcolumncell">
 <%
-	    if (outputName.length() == 0)
-	    {
+		if (connectionName.length() == 0)
+		{
 %>
-				<td class="description"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.OutputConnectionColon")%></nobr></td>
-				<td class="value">
-					<select name="outputname" size="1">
-						<option <%="".equals(outputName)?"selected=\"selected\"":""%> value="">-- <%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.NoneSelected")%> --</option>
+								<select name="connectionname" size="1">
+									<option <%="".equals(connectionName)?"selected=\"selected\"":""%> value="">-- <%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.NoneSelected")%> --</option>
 <%
-		int j = 0;
-		while (j < outputList.length)
+			for (IRepositoryConnection conn : connList)
+			{
+%>
+									<option <%=conn.getName().equals(connectionName)?"selected=\"selected\"":""%> value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(conn.getName())%>'><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(conn.getName())%></option>
+<%
+			}
+%>
+								</select>
+<%
+		}
+		else
 		{
-			IOutputConnection conn = outputList[j++];
 %>
-						<option <%=conn.getName().equals(outputName)?"selected=\"selected\"":""%> value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(conn.getName())%>'><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(conn.getName())%></option>
+								<input type="hidden" name="connectionname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(connectionName)%>'/><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(connectionName)%>
 <%
 		}
 %>
-					</select>
-				</td>
+							</td>
+						</tr>
 <%
-	    }
-	    else
-	    {
+		for (int j = 0; j < transformationNames.length; j++)
+		{
+			String transformationName = transformationNames[j];
+			String transformationDescription = transformationDescriptions[j];
 %>
-				<td class="description"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.OutputConnectionColon")%></nobr></td>
-				<td class="value"><input type="hidden" name="outputname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(outputName)%>'/><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(outputName)%></td>
+						<tr class="<%=((displaySequence % 2)==0)?"evenformrow":"oddformrow"%>">
+							<td class="formcolumncell">
+								<input name="pipeline_<%=j%>_op" type="hidden" value="Continue"/>
+								<a name="pipeline_<%=j%>_tag"/>
+								<input type="button" value="<%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.Delete")%>" alt='<%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.Deletestage")%>' onclick="javascript:DeletePipelineStage(<%=j%>);"/>
+								<input type="button" value="<%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.InsertBefore")%>" alt='<%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.Insertnewstagehere")%>' onclick="javascript:InsertPipelineStage(<%=j%>);"/>
+							</td>
+							<td class="formcolumncell"><%=(++displaySequence)%>.</td>
+							<td class="formcolumncell">
+								<input name="pipeline_<%=j%>_description" type="text" size="30" value="<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(transformationDescription)%>"/>
+							</td>
+							<td class="formcolumncell">
+								<nobr><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(transformationName)%></nobr>
+								<input name="pipeline_<%=j%>_connectionname" type="hidden" value="<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(transformationName)%>"/>
+							</td>
+						</tr>
 <%
-	    }
+		}
 %>
-
+						<tr class="<%=((displaySequence % 2)==0)?"evenformrow":"oddformrow"%>">
+							<td class="formcolumncell">
 <%
-	    if (connectionName.length() == 0)
-	    {
+		if (transformationList.length > 0)
+		{
 %>
-				<td class="description"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.RepositoryConnectionColon")%></nobr></td>
-				<td class="value">
-					<select name="connectionname" size="1">
-						<option <%="".equals(connectionName)?"selected=\"selected\"":""%> value="">-- <%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.NoneSelected")%> --</option>
+								<input type="button" value="<%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.InsertBefore")%>" alt='<%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.Insertnewstagehere")%>' onclick="javascript:AppendPipelineStage();"/>
 <%
-		int j = 0;
-		while (j < connList.length)
+		}
+%>
+							</td>
+							<td class="formcolumncell"><%=(++displaySequence)%>.</td>
+							<td class="formcolumncell"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.OutputStage")%></td>
+							<td class="formcolumncell">
+<%
+		if (outputName.length() == 0)
 		{
-			IRepositoryConnection conn = connList[j++];
 %>
-						<option <%=conn.getName().equals(connectionName)?"selected=\"selected\"":""%> value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(conn.getName())%>'><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(conn.getName())%></option>
+								<select name="outputname" size="1">
+									<option <%="".equals(outputName)?"selected=\"selected\"":""%> value="">-- <%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.NoneSelected")%> --</option>
+<%
+			for (IOutputConnection conn : outputList)
+			{
+%>
+									<option <%=conn.getName().equals(outputName)?"selected=\"selected\"":""%> value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(conn.getName())%>'><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(conn.getName())%></option>
+<%
+			}
+%>
+								</select>
 <%
 		}
+		else
+		{
 %>
-					</select>
-				</td>
+								<input type="hidden" name="outputname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(outputName)%>'/><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(outputName)%>
 <%
-	    }
-	    else
-	    {
+		}
 %>
-				<td class="description"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.RepositoryConnectionColon")%></nobr></td>
-				<td class="value"><input type="hidden" name="connectionname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(connectionName)%>'/><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(connectionName)%></td>
+							</td>
+						</tr>
 <%
-	    }
+		if (transformationList.length > 0)
+		{
+%>
+						<tr class="formrow"><td class="formseparator" colspan="4"><hr/></td></tr>
+						<tr class="formrow">
+							<td class="formcolumncell">
+								<input name="pipeline_op" type="hidden" value="Continue"/>
+								<a name="pipeline_tag"/>
+							</td>
+							<td class="formcolumncell">
+							</td>
+							<td class="formcolumncell">
+								<input name="pipeline_description" type="text" size="30" value=""/>
+							</td>
+							<td class="formcolumncell">
+								<select name="pipeline_connectionname" size="1">
+									<option selected="selected" value="">-- <%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.NoneSelected")%> --</option>
+<%
+			for (ITransformationConnection conn : transformationList)
+			{
+%>
+									<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>
 				<td class="description"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editjob.PriorityColon")%></nobr></td>
 				<td class="value">
@@ -853,12 +1181,25 @@
 %>
 		  <input type="hidden" name="outputname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(outputName)%>'/>
 		  <input type="hidden" name="connectionname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(connectionName)%>'/>
+		  <input type="hidden" name="pipeline_count" value="<%=transformationNames.length%>"/>
+<%
+		for (int j = 0; j < transformationNames.length; j++)
+		{
+			String transformationName = transformationNames[j];
+			String transformationDescription = transformationDescriptions[j];
+%>
+		  <input type="hidden" name="pipeline_<%=j%>_connectionname" value="<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(transformationName)%>"/>
+		  <input type="hidden" name="pipeline_<%=j%>_description" value="<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(transformationDescription)%>"/>
+<%
+		}
+%>
+		  <input type="hidden" name="priority" value='<%=priority%>'/>
 		  <input type="hidden" name="startmethod" value='<%=startMethod%>'/>
 <%
 	}
 
 	// Scheduling tab
-	if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.Scheduling")))
+	if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.Scheduling")) && tabSequenceInt == -1)
 	{
 %>
 		  <table class="displaytable">
@@ -1322,7 +1663,7 @@
 		{
 			try
 			{
-				outputConnector.outputSpecificationBody(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),outputSpecification,tabName);
+				outputConnector.outputSpecificationBody(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),outputSpecification,1,tabSequenceInt,tabName);
 			}
 			finally
 			{
@@ -1341,7 +1682,7 @@
 		{
 			try
 			{
-				repositoryConnector.outputSpecificationBody(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),documentSpecification,tabName);
+				repositoryConnector.outputSpecificationBody(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),documentSpecification,0,tabSequenceInt,tabName);
 			}
 			finally
 			{
@@ -1365,7 +1706,7 @@
 	}
 	else
 	{
-		if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.Connection")))
+		if (tabName.equals(Messages.getString(pageContext.getRequest().getLocale(),"editjob.Connection")) && tabSequenceInt == -1)
 		{
 %>
 			<input type="button" value="<%=Messages.getAttributeString(pageContext.getRequest().getLocale(),"editjob.Continue")%>" onClick="javascript:Continue()" alt="<%=Messages.getAttributeString(pageContext.getRequest().getLocale(),"editjob.ContinueToNextScreen")%>"/>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editmapper.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editmapper.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editmapper.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editmapper.jsp Mon Jun  9 23:19:08 2014
@@ -92,6 +92,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
@@ -245,11 +247,33 @@
 	{
 %>
 	<form class="standardform" name="editconnection" action="execute.jsp" method="POST" enctype="multipart/form-data">
-	  <input type="hidden" name="op" value="Continue"/>
-	  <input type="hidden" name="type" value="mapper"/>
-	  <input type="hidden" name="tabname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(tabName)%>'/>
-	  <input type="hidden" name="isnewconnection" value='<%=(isNew?"true":"false")%>'/>
+	    <input type="hidden" name="op" value="Continue"/>
+	    <input type="hidden" name="type" value="mapper"/>
+	    <input type="hidden" name="tabname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(tabName)%>'/>
+	    <input type="hidden" name="isnewconnection" value='<%=(isNew?"true":"false")%>'/>
 	    <table class="tabtable">
+	      <tr class="tabspacerrow">
+		<td class="spacertab" colspan="<%=tabsArray.size()%>"></td>
+		<td class="remaindertab" rowspan="3">
+<%
+	  if (description.length() > 0)
+	  {
+%>
+			  <nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editmapper.EditMapping")%> '<%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(description)%>'</nobr>
+<%
+	  }
+	  else
+	  {
+%>
+		          <nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editmapper.EditAMapping")%></nobr>
+<%
+	  }
+%>
+		</td>
+	      </tr>
+	      <tr class="tabsequencerow">
+		<td class="blanksequencetab" colspan="<%=tabsArray.size()%>"></td>
+	      </tr>
 	      <tr class="tabrow">
 <%
 	  int tabNum = 0;
@@ -270,22 +294,6 @@
 		}
 	  }
 %>
-		      <td class="remaindertab">
-<%
-	  if (description.length() > 0)
-	  {
-%>
-			  <nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editmapper.EditMapping")%> '<%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(description)%>'</nobr>
-<%
-	  }
-	  else
-	  {
-%>
-		          <nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editmapper.EditAMapping")%></nobr>
-<%
-	  }
-%>
-		      </td>
 	      </tr>
 	      <tr class="tabbodyrow">
 		<td class="tabbody" colspan='<%=Integer.toString(tabsArray.size()+1)%>'>

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=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editoutput.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/editoutput.jsp Mon Jun  9 23:19:08 2014
@@ -87,6 +87,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
@@ -238,11 +240,34 @@
 %>
 
 	<form class="standardform" name="editconnection" action="execute.jsp" method="POST" enctype="multipart/form-data">
-	  <input type="hidden" name="op" value="Continue"/>
-	  <input type="hidden" name="type" value="output"/>
-	  <input type="hidden" name="tabname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(tabName)%>'/>
-	  <input type="hidden" name="isnewconnection" value='<%=(isNew?"true":"false")%>'/>
+	    <input type="hidden" name="op" value="Continue"/>
+	    <input type="hidden" name="type" value="output"/>
+	    <input type="hidden" name="tabname" value='<%=org.apache.manifoldcf.ui.util.Encoder.attributeEscape(tabName)%>'/>
+	    <input type="hidden" name="isnewconnection" value='<%=(isNew?"true":"false")%>'/>
 	    <table class="tabtable">
+	      <tr class="tabspacerrow">
+		<td class="spacertab" colspan="<%=tabsArray.size()%>"></td>
+		<td class="remaindertab" rowspan="3">
+<%
+	  if (description.length() > 0)
+	  {
+%>
+			<nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editoutput.EditOutputConnection")%> '<%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(description)%>'</nobr>
+<%
+	  }
+	  else
+	  {
+%>
+
+		          <nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editoutput.EditAnOutputConnection")%></nobr>
+<%
+	  }
+%>
+		</td>
+	      </tr>
+	      <tr class="tabsequencerow">
+		<td class="blanksequencetab" colspan="<%=tabsArray.size()%>"></td>
+	      </tr>
 	      <tr class="tabrow">
 <%
 	  int tabNum = 0;
@@ -263,23 +288,6 @@
 		}
 	  }
 %>
-		      <td class="remaindertab">
-<%
-	  if (description.length() > 0)
-	  {
-%>
-			  <nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editoutput.EditOutputConnection")%> '<%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(description)%>'</nobr>
-<%
-	  }
-	  else
-	  {
-%>
-
-		          <nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"editoutput.EditAnOutputConnection")%></nobr>
-<%
-	  }
-%>
-		      </td>
 	      </tr>
 	      <tr class="tabbodyrow">
 		<td class="tabbody" colspan='<%=Integer.toString(tabsArray.size()+1)%>'>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/error.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/error.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/error.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/error.jsp Mon Jun  9 23:19:08 2014
@@ -22,6 +22,10 @@
 */
 %>
 
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
 	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

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=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/execute.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/execute.jsp Mon Jun  9 23:19:08 2014
@@ -50,8 +50,10 @@
 		IAuthorityConnectionManager authConnManager = AuthorityConnectionManagerFactory.make(threadContext);
 		IMappingConnectionManager mappingConnManager = MappingConnectionManagerFactory.make(threadContext);
 		IOutputConnectionManager outputManager = OutputConnectionManagerFactory.make(threadContext);
+		ITransformationConnectionManager transformationManager = TransformationConnectionManagerFactory.make(threadContext);
 		
 		IOutputConnectorPool outputConnectorPool = OutputConnectorPoolFactory.make(threadContext);
+		ITransformationConnectorPool transformationConnectorPool = TransformationConnectorPoolFactory.make(threadContext);
 		IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
 		
 		String type = variableContext.getParameter("type");
@@ -748,6 +750,121 @@
 <%
 			}
 		}
+		else if (type != null && op != null && type.equals("transformation"))
+		{
+			// -- Output 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.
+					ITransformationConnection 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 = transformationManager.load(connectionName);
+					}
+					
+					if (connection == null)
+					{
+						connection = transformationManager.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 = TransformationConnectorFactory.processConfigurationPost(threadContext,connection.getClassName(),variableContext,pageContext.getRequest().getLocale(),connection.getConfigParams());
+					
+					if (error != null)
+					{
+						variableContext.setParameter("text",error);
+						variableContext.setParameter("target","listtransformations.jsp");
+%>
+						<jsp:forward page="error.jsp"/>
+<%
+					}
+					
+					if (op.equals("Continue"))
+					{
+						threadContext.save("ConnectionObject",connection);
+%>
+						<jsp:forward page="edittransformation.jsp"/>
+<%
+					}
+					else if (op.equals("Save"))
+					{
+						transformationManager.save(connection);
+						variableContext.setParameter("connname",connectionName);
+%>
+						<jsp:forward page="viewtransformation.jsp"/>
+<%
+					}
+				}
+				catch (ManifoldCFException e)
+				{
+					e.printStackTrace();
+					variableContext.setParameter("text",e.getMessage());
+					variableContext.setParameter("target","listtransformations.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");
+					transformationManager.delete(connectionName);
+%>
+					<jsp:forward page="listtransformations.jsp"/>
+<%
+				}
+				catch (ManifoldCFException e)
+				{
+					e.printStackTrace();
+					variableContext.setParameter("text",e.getMessage());
+					variableContext.setParameter("target","listtransformations.jsp");
+%>
+					<jsp:forward page="error.jsp"/>
+<%
+				}
+			}
+			else if (op.equals("Cancel"))
+			{
+%>
+				<jsp:forward page="listtransformations.jsp"/>
+<%
+			}
+			else
+			{
+				// Error
+				variableContext.setParameter("text","Illegal parameter to transformation connection execution page");
+				variableContext.setParameter("target","listtransformations.jsp");
+%>
+				<jsp:forward page="error.jsp"/>
+<%
+			}
+		}
 		else if (type != null && op != null && type.equals("job"))
 		{
 			// -- Job editing operations --
@@ -789,6 +906,21 @@
 					x = variableContext.getParameter("hopcountmode");
 					if (x != null)
 						job.setHopcountMode(Integer.parseInt(x));
+					x = variableContext.getParameter("pipeline_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.clearPipeline();
+						for (int j = 0; j < count; j++)
+						{
+							// Gather everything first; we'll look at edits later
+							String connectionName = variableContext.getParameter("pipeline_"+j+"_connectionname");
+							String description = variableContext.getParameter("pipeline_"+j+"_description");
+							job.addPipelineStage(connectionName, description);
+						}
+					}
 
 					x = variableContext.getParameter("schedulerecords");
 					String[] y;
@@ -1066,7 +1198,7 @@
 						{
 							try
 							{
-								String error = outputConnector.processSpecificationPost(variableContext,pageContext.getRequest().getLocale(),job.getOutputSpecification());
+								String error = outputConnector.processSpecificationPost(variableContext,pageContext.getRequest().getLocale(),job.getOutputSpecification(),1+job.countPipelineStages());
 								if (error != null)
 								{
 									variableContext.setParameter("text",error);
@@ -1090,7 +1222,7 @@
 						{
 							try
 							{
-								String error = repositoryConnector.processSpecificationPost(variableContext,pageContext.getRequest().getLocale(),job.getSpecification());
+								String error = repositoryConnector.processSpecificationPost(variableContext,pageContext.getRequest().getLocale(),job.getSpecification(),0);
 								if (error != null)
 								{
 									variableContext.setParameter("text",error);
@@ -1107,6 +1239,65 @@
 						}
 					}
 					
+					// Process all pipeline stages
+					for (int j = 0; j < job.countPipelineStages(); j++)
+					{
+						ITransformationConnection transformationConnection = transformationManager.load(job.getPipelineStageConnectionName(j));
+						if (transformationConnection != null)
+						{
+							ITransformationConnector transformationConnector = transformationConnectorPool.grab(transformationConnection);
+							if (transformationConnector != null)
+							{
+								try
+								{
+									String error = transformationConnector.processSpecificationPost(variableContext,pageContext.getRequest().getLocale(),job.getPipelineStageSpecification(j),1+j);
+									if (error != null)
+									{
+										variableContext.setParameter("text",error);
+										variableContext.setParameter("target","listjobs.jsp");
+%>
+									<jsp:forward page="error.jsp"/>
+<%
+									}
+								}
+								finally
+								{
+									transformationConnectorPool.release(transformationConnection,transformationConnector);
+								}
+							}
+						}
+					}
+					
+					// Now, after gathering is complete, consider doing changes to the pipeline.
+					int currentStage = 0;
+					for (int j = 0; j < job.countPipelineStages(); j++)
+					{
+						// Look at the operation
+						x = variableContext.getParameter("pipeline_"+j+"_op");
+						if (x != null && x.equals("Delete"))
+						{
+							// Delete this pipeline stage
+							job.deletePipelineStage(currentStage);
+						}
+						else if (x != null && x.equals("Insert"))
+						{
+							// Insert a new stage before this one
+							String connectionName = variableContext.getParameter("pipeline_connectionname");
+							String description = variableContext.getParameter("pipeline_description");
+							job.insertPipelineStage(currentStage++,connectionName,description);
+						}
+						else
+							currentStage++;
+					}
+					x = variableContext.getParameter("pipeline_op");
+					if (x != null && x.equals("Add"))
+					{
+						// Append a new stage at the end
+						String connectionName = variableContext.getParameter("pipeline_connectionname");
+						String description = variableContext.getParameter("pipeline_description");
+						job.addPipelineStage(connectionName,description);
+					}
+					
 					if (op.equals("Continue"))
 					{
 						threadContext.save("JobObject",job);

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/index.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/index.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/index.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/index.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listauthorities.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listauthorities.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listauthorities.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listauthorities.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listconnections.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listconnections.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listconnections.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listconnections.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listgroups.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listgroups.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listgroups.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listgroups.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listjobs.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listjobs.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listjobs.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listjobs.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listmappers.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listmappers.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listmappers.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listmappers.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listoutputs.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listoutputs.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listoutputs.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/listoutputs.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/login.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/login.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/login.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/login.jsp Mon Jun  9 23:19:08 2014
@@ -26,6 +26,8 @@ response.setContentType("text/html;chars
 */
 %>
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 	<head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/maxactivityreport.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/maxactivityreport.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/maxactivityreport.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/maxactivityreport.jsp Mon Jun  9 23:19:08 2014
@@ -25,6 +25,8 @@ boolean maintenanceUnderway = org.apache
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/maxbandwidthreport.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/maxbandwidthreport.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/maxbandwidthreport.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/maxbandwidthreport.jsp Mon Jun  9 23:19:08 2014
@@ -25,6 +25,8 @@ boolean maintenanceUnderway = org.apache
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

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=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/navigation.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/navigation.jsp Mon Jun  9 23:19:08 2014
@@ -31,6 +31,9 @@
 <p class="menumain"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"navigation.Outputs")%></nobr></p>
 <ul class="menusecond">
 	<li class="menuitem">
+		<nobr><a class="menulink" href="listtransformations.jsp" alt="<%=Messages.getAttributeString(pageContext.getRequest().getLocale(),"navigation.Listtransformationconnections")%>"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"navigation.ListTransformationConnections")%></a></nobr>
+	</li>
+	<li class="menuitem">
 		<nobr><a class="menulink" href="listoutputs.jsp" alt="<%=Messages.getAttributeString(pageContext.getRequest().getLocale(),"navigation.Listoutputconnections")%>"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"navigation.ListOutputConnections")%></a></nobr>
 	</li>
 </ul>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/queuestatus.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/queuestatus.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/queuestatus.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/queuestatus.jsp Mon Jun  9 23:19:08 2014
@@ -24,8 +24,9 @@ boolean maintenanceUnderway = org.apache
 
 %>
 
-
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/resultreport.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/resultreport.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/resultreport.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/resultreport.jsp Mon Jun  9 23:19:08 2014
@@ -25,6 +25,8 @@ boolean maintenanceUnderway = org.apache
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/showjobstatus.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/showjobstatus.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/showjobstatus.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/showjobstatus.jsp Mon Jun  9 23:19:08 2014
@@ -24,8 +24,6 @@ boolean maintenanceUnderway = org.apache
 
 %>
 
-<?xml version="1.0" encoding="utf-8"?>
-
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
 	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/simplereport.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/simplereport.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/simplereport.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/simplereport.jsp Mon Jun  9 23:19:08 2014
@@ -24,8 +24,9 @@ boolean maintenanceUnderway = org.apache
 
 %>
 
-
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/style.css
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/style.css?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/style.css (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/style.css Mon Jun  9 23:19:08 2014
@@ -38,6 +38,55 @@ body
     border-collapse: collapse;
 }
 
+.tabspacerrow
+{
+    height: 3px;
+}
+
+.spacertab
+{
+    background: #f8f8f8;
+    border-style: solid;
+    border-width: 1px 0 0 1px;
+    border-color: #ccc #ccc #ccc #ccc;
+    margin: 0;
+    padding: 0px 0px 0px 0px;
+    vertical-align: top;
+    height: 3px;
+}
+
+.tabsequencerow
+{
+    height: 8px;
+    font-size: 8px;
+    line-height: 8px;
+}
+
+.blanksequencetab
+{
+    background: #f8f8f8;
+    border-style: solid;
+    border-width: 0 0 0 1px;
+    border-color: #ccc #ccc #229ddb #ccc;
+    margin: 0;
+    padding: 2px 10px 3px 10px;
+    vertical-align: top;
+    height: 8px;
+}
+
+.sequencetab
+{
+    background: #fcfcfc;
+    border-style: solid;
+    border-width: 1px 1px 0 1px;
+    border-color: #ccc #ccc #229ddb #ccc;
+    margin: 0;
+    padding: 2px 10px 3px 10px;
+    height: 8px;
+    vertical-align: top;
+	text-align: center;
+}
+
 .tabrow
 {
     height: 20px;
@@ -52,7 +101,7 @@ body
 
 .passivetab
 {
-    background: #f8f8f8;
+    background: #fcfcfc;
     border: solid 1px;
     border-color: #ccc #ccc #229ddb #ccc;
     margin: 0;
@@ -82,17 +131,18 @@ body
     border-style: solid;
     border-width: 1px 1px 1px 0;
     border-color: #ccc #ccc #229ddb;
-    padding: 4px 10px 5px 10px;
-    height: 20px;
+    padding: 18px 10px 2px 10px;
+    height: 28px;
     vertical-align: top;
     text-align: right;
+	font-size: 12px;
     color: #555;
 }
 
 .tabbody
 {
     height: 100%;
-    border-left: #229ddb solid 1px;
+    border-left: #229ddb solid 2px;
     margin: 0;
     padding: 10px;
     vertical-align: top;

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewauthority.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewauthority.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewauthority.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewauthority.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewconnection.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewconnection.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewconnection.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewconnection.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewgroup.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewgroup.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewgroup.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewgroup.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

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=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewjob.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewjob.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
@@ -80,10 +82,12 @@
 	IJobManager manager = JobManagerFactory.make(threadContext);
         IOutputConnectionManager outputManager = OutputConnectionManagerFactory.make(threadContext);
 	IRepositoryConnectionManager connManager = RepositoryConnectionManagerFactory.make(threadContext);
-	
+	ITransformationConnectionManager transformationManager = TransformationConnectionManagerFactory.make(threadContext);
+
 	IOutputConnectorPool outputConnectorPool = OutputConnectorPoolFactory.make(threadContext);
 	IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
-	
+	ITransformationConnectorPool transformationConnectorPool = TransformationConnectorPoolFactory.make(threadContext);
+
 	String jobID = variableContext.getParameter("jobid");
 	IJobDescription job = manager.load(new Long(jobID));
 	if (job == null)
@@ -150,6 +154,8 @@
 		//threadContext.save("OutputConnection",outputConnection);
 		//threadContext.save("DocumentSpecification",job.getSpecification());
 		//threadContext.save("RepositoryConnection",connection);
+		int displaySequence = 0;
+
 %>
 		<table class="displaytable">
 			<tr>
@@ -163,10 +169,40 @@
 				<td class="separator" colspan="4"><hr/></td>
 			</tr>
 			<tr>
-				<td class="description"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"viewjob.OutputConnectionColon")%></nobr></td>
-				<td class="value"><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(job.getOutputConnectionName())%></td>
-				<td class="description"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"viewjob.RepositoryConnectionColon")%></nobr></td>
-				<td class="value"><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(job.getConnectionName())%></td>
+				<td class="description" colspan="1"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"viewjob.PipelineColon")%></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.StageDescription")%></nobr></td>
+							<td class="formcolumnheader"><nobr><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"viewjob.StageConnectionName")%></nobr></td>
+						</tr>
+						<tr class="<%=((displaySequence % 2)==0)?"evenformrow":"oddformrow"%>">
+							<td class="formcolumncell"><%=(++displaySequence)%>.</td>
+							<td class="formcolumncell"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"viewjob.RepositoryStage")%></td>
+							<td class="formcolumncell"><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(job.getConnectionName())%></td>
+						</tr>
+<%
+		for (int j = 0; j < job.countPipelineStages(); j++)
+		{
+			String transformationConnectionName = job.getPipelineStageConnectionName(j);
+			String transformationDescription = job.getPipelineStageDescription(j);
+%>
+						<tr class="<%=((displaySequence % 2)==0)?"evenformrow":"oddformrow"%>">
+							<td class="formcolumncell"><%=(++displaySequence)%>.</td>
+							<td class="formcolumncell"><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(transformationDescription)%></td>
+							<td class="formcolumncell"><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(transformationConnectionName)%></td>
+						</tr>
+<%
+		}
+%>
+						<tr class="<%=((displaySequence % 2)==0)?"evenformrow":"oddformrow"%>">
+							<td class="formcolumncell"><%=(++displaySequence)%>.</td>
+							<td class="formcolumncell"><%=Messages.getBodyString(pageContext.getRequest().getLocale(),"viewjob.OutputStage")%></td>
+							<td class="formcolumncell"><%=org.apache.manifoldcf.ui.util.Encoder.bodyEscape(job.getOutputConnectionName())%></td>
+						</tr>
+					</table>
+				</td>
 			</tr>
 			<tr>
 				<td class="separator" colspan="4"><hr/></td>
@@ -657,7 +693,7 @@
 			{
 				try
 				{
-					outputConnector.viewSpecification(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),job.getOutputSpecification());
+					outputConnector.viewSpecification(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),job.getOutputSpecification(),1);
 				}
 				finally
 				{
@@ -681,7 +717,7 @@
 			{
 				try
 				{
-					repositoryConnector.viewSpecification(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),job.getSpecification());
+					repositoryConnector.viewSpecification(new org.apache.manifoldcf.ui.jsp.JspWrapper(out,adminprofile),pageContext.getRequest().getLocale(),job.getSpecification(),0);
 				}
 				finally
 				{

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewmapper.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewmapper.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewmapper.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewmapper.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewoutput.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewoutput.jsp?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewoutput.jsp (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/webapp/viewoutput.jsp Mon Jun  9 23:19:08 2014
@@ -23,6 +23,8 @@
 %>
 
 <?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>

Modified: manifoldcf/trunk/framework/example-common/connectors.xml
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/example-common/connectors.xml?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/example-common/connectors.xml (original)
+++ manifoldcf/trunk/framework/example-common/connectors.xml Mon Jun  9 23:19:08 2014
@@ -28,7 +28,9 @@
     <!-- authorizationdomain domain="FB" name="FaceBook"/-->
 
     <!-- Add your output connectors here -->
-    
+
+    <!-- Add your transformation connectors here -->
+
     <!-- Add your mapping connectors here -->
     
     <!-- Add your authority connectors here -->

Modified: manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/connectors/BaseRepositoryConnector.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/connectors/BaseRepositoryConnector.java?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/connectors/BaseRepositoryConnector.java (original)
+++ manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/connectors/BaseRepositoryConnector.java Mon Jun  9 23:19:08 2014
@@ -461,6 +461,24 @@ public abstract class BaseRepositoryConn
   // receives a thread context argument for all UI methods, while the second bunch does not need one (since it has already been applied via the connect()
   // method, above).
 
+  /** Obtain the name of the form check javascript method to call.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
+  *@return the name of the form check javascript method.
+  */
+  public String getFormCheckJavascriptMethodName(int connectionSequenceNumber)
+  {
+    return "checkSpecification";
+  }
+
+  /** Obtain the name of the form presave check javascript method to call.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
+  *@return the name of the form presave check javascript method.
+  */
+  public String getFormPresaveCheckJavascriptMethodName(int connectionSequenceNumber)
+  {
+    return "checkSpecificationForSave";
+  }
+
   /** Output the specification header section.
   * This method is called in the head section of a job page which has selected a repository connection of the
   * current type.  Its purpose is to add the required tabs to the list, and to output any javascript methods
@@ -469,15 +487,34 @@ public abstract class BaseRepositoryConn
   *@param out is the output to which any HTML should be sent.
   *@param locale is the locale the output is preferred to be in.
   *@param ds is the current document specification for this job.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
   *@param tabsArray is an array of tab names.  Add to this array any tab names that are specific to the connector.
   */
   @Override
+  public void outputSpecificationHeader(IHTTPOutput out, Locale locale, DocumentSpecification ds,
+    int connectionSequenceNumber, List<String> tabsArray)
+    throws ManifoldCFException, IOException
+  {
+    outputSpecificationHeader(out,locale,ds,tabsArray);
+  }
+  
+  /** Output the specification header section.
+  * This method is called in the head section of a job page which has selected a repository connection of the
+  * current type.  Its purpose is to add the required tabs to the list, and to output any javascript methods
+  * that might be needed by the job editing HTML.
+  * The connector will be connected before this method can be called.
+  *@param out is the output to which any HTML should be sent.
+  *@param locale is the locale the output is preferred to be in.
+  *@param ds is the current document specification for this job.
+  *@param tabsArray is an array of tab names.  Add to this array any tab names that are specific to the connector.
+  */
   public void outputSpecificationHeader(IHTTPOutput out, Locale locale, DocumentSpecification ds, List<String> tabsArray)
     throws ManifoldCFException, IOException
   {
     outputSpecificationHeader(out,ds,tabsArray);
   }
 
+
   /** Output the specification header section.
   * This method is called in the head section of a job page which has selected a repository connection of the current type.  Its purpose is to add the required tabs
   * to the list, and to output any javascript methods that might be needed by the job editing HTML.
@@ -511,9 +548,30 @@ public abstract class BaseRepositoryConn
   *@param out is the output to which any HTML should be sent.
   *@param locale is the locale the output is preferred to be in.
   *@param ds is the current document specification for this job.
-  *@param tabName is the current tab name.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
+  *@param actualSequenceNumber is the connection within the job that has currently been selected.
+  *@param tabName is the current tab name.  (actualSequenceNumber, tabName) form a unique tuple within
+  *  the job.
   */
   @Override
+  public void outputSpecificationBody(IHTTPOutput out, Locale locale, DocumentSpecification ds,
+    int connectionSequenceNumber, int actualSequenceNumber, String tabName)
+    throws ManifoldCFException, IOException
+  {
+    outputSpecificationBody(out,locale,ds,tabName);
+  }
+
+  /** Output the specification body section.
+  * This method is called in the body section of a job page which has selected a repository connection of the
+  * current type.  Its purpose is to present the required form elements for editing.
+  * The coder can presume that the HTML that is output from this configuration will be within appropriate
+  *  <html>, <body>, and <form> tags.  The name of the form is always "editjob".
+  * The connector will be connected before this method can be called.
+  *@param out is the output to which any HTML should be sent.
+  *@param locale is the locale the output is preferred to be in.
+  *@param ds is the current document specification for this job.
+  *@param tabName is the current tab name.
+  */
   public void outputSpecificationBody(IHTTPOutput out, Locale locale, DocumentSpecification ds, String tabName)
     throws ManifoldCFException, IOException
   {
@@ -541,10 +599,29 @@ public abstract class BaseRepositoryConn
   *@param variableContext contains the post data, including binary file-upload information.
   *@param locale is the locale the output is preferred to be in.
   *@param ds is the current document specification for this job.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
   *@return null if all is well, or a string error message if there is an error that should prevent saving of
   * the job (and cause a redirection to an error page).
   */
   @Override
+  public String processSpecificationPost(IPostParameters variableContext, Locale locale, DocumentSpecification ds,
+    int connectionSequenceNumber)
+    throws ManifoldCFException
+  {
+    return processSpecificationPost(variableContext,locale,ds);
+  }
+
+  /** Process a specification post.
+  * This method is called at the start of job's edit or view page, whenever there is a possibility that form
+  * data for a connection has been posted.  Its purpose is to gather form information and modify the
+  * document specification accordingly.  The name of the posted form is always "editjob".
+  * The connector will be connected before this method can be called.
+  *@param variableContext contains the post data, including binary file-upload information.
+  *@param locale is the locale the output is preferred to be in.
+  *@param ds is the current document specification for this job.
+  *@return null if all is well, or a string error message if there is an error that should prevent saving of
+  * the job (and cause a redirection to an error page).
+  */
   public String processSpecificationPost(IPostParameters variableContext, Locale locale, DocumentSpecification ds)
     throws ManifoldCFException
   {
@@ -573,8 +650,25 @@ public abstract class BaseRepositoryConn
   *@param out is the output to which any HTML should be sent.
   *@param locale is the locale the output is preferred to be in.
   *@param ds is the current document specification for this job.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
   */
   @Override
+  public void viewSpecification(IHTTPOutput out, Locale locale, DocumentSpecification ds,
+    int connectionSequenceNumber)
+    throws ManifoldCFException, IOException
+  {
+    viewSpecification(out,locale,ds);
+  }
+
+  /** View specification.
+  * This method is called in the body section of a job's view page.  Its purpose is to present the document
+  * specification information to the user.  The coder can presume that the HTML that is output from
+  * this configuration will be within appropriate <html> and <body> tags.
+  * The connector will be connected before this method can be called.
+  *@param out is the output to which any HTML should be sent.
+  *@param locale is the locale the output is preferred to be in.
+  *@param ds is the current document specification for this job.
+  */
   public void viewSpecification(IHTTPOutput out, Locale locale, DocumentSpecification ds)
     throws ManifoldCFException, IOException
   {

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=1601529&r1=1601528&r2=1601529&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 Mon Jun  9 23:19:08 2014
@@ -91,6 +91,53 @@ public interface IJobDescription
   */
   public String getOutputConnectionName();
 
+  /** Clear pipeline connections.
+  */
+  public void clearPipeline();
+  
+  /** Add a pipeline connection.
+  *@param pipelineStageConnectionName is the name of the pipeline connection to add.
+  *@param pipelineStageDescription is a description of the pipeline stage being added.
+  *@return the empty output specification for this pipeline stage.
+  */
+  public OutputSpecification addPipelineStage(String pipelineStageConnectionName, String pipelineStageDescription);
+  
+  /** Get a count of pipeline connections.
+  *@return the current number of pipeline connections.
+  */
+  public int countPipelineStages();
+  
+  /** Get a specific pipeline connection name.
+  *@param index is the index of the pipeline stage whose connection name to get.
+  *@return the name of the connection.
+  */
+  public String getPipelineStageConnectionName(int index);
+
+  /** Get a specific pipeline stage description.
+  *@param index is the index of the pipeline stage whose description to get.
+  *@return the name of the connection.
+  */
+  public String getPipelineStageDescription(int index);
+
+  /** Get a specific pipeline stage specification.
+  *@param index is the index of the pipeline stage whose specification is needed.
+  *@return the specification for the connection.
+  */
+  public OutputSpecification getPipelineStageSpecification(int index);
+
+  /** Delete a pipeline stage.
+  *@param index is the index of the pipeline stage to delete.
+  */
+  public void deletePipelineStage(int index);
+  
+  /** Insert a new pipeline stage.
+  *@param index is the index to insert pipeline stage before
+  *@param pipelineStageConnectionName is the connection name.
+  *@param pipelineStageDescription is the description.
+  *@return the newly-created output specification.
+  */
+  public OutputSpecification insertPipelineStage(int index, String pipelineStageConnectionName, String pipelineStageDescription);
+  
   /** 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=1601529&r1=1601528&r2=1601529&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 Mon Jun  9 23:19:08 2014
@@ -125,6 +125,13 @@ public interface IJobManager
   public boolean checkIfOutputReference(String connectionName)
     throws ManifoldCFException;
 
+  /** See if there's a reference to a transformation connection name.
+  *@param connectionName is the name of the connection.
+  *@return true if there is a reference, false otherwise.
+  */
+  public boolean checkIfTransformationReference(String connectionName)
+    throws ManifoldCFException;
+
   /** Get the job IDs associated with a given connection name.
   *@param connectionName is the name of the connection.
   *@return the set of job id's associated with that connection.
@@ -955,6 +962,33 @@ public interface IJobManager
   public void noteOutputConnectionChange(String connectionName)
     throws ManifoldCFException;
 
+  /**  Note the deregistration of a transformation 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 noteTransformationConnectorDeregistration(String[] connectionNames)
+    throws ManifoldCFException;
+
+  /** Note the registration of a transformation 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 noteTransformationConnectorRegistration(String[] connectionNames)
+    throws ManifoldCFException;
+
+  /** Note a change in transformation connection configuration.
+  * This method will be called whenever a connection's configuration is modified.
+  */
+  public void noteTransformationConnectionChange(String connectionName)
+    throws ManifoldCFException;
+
+  /** Assess jobs marked to be in need of assessment for connector status changes.
+  */
+  public void assessMarkedJobs()
+    throws ManifoldCFException;
+
   /** Delete jobs in need of being deleted (which are marked "ready for delete").
   * This method is meant to be called periodically to perform delete processing on jobs.
   */

Modified: manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IRepositoryConnector.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IRepositoryConnector.java?rev=1601529&r1=1601528&r2=1601529&view=diff
==============================================================================
--- manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IRepositoryConnector.java (original)
+++ manifoldcf/trunk/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/interfaces/IRepositoryConnector.java Mon Jun  9 23:19:08 2014
@@ -252,7 +252,19 @@ public interface IRepositoryConnector ex
   // the current connector object is connected, while the second group can.  That is why the first group
   // receives a thread context argument for all UI methods, while the second group does not need one
   // (since it has already been applied via the connect() method).
-    
+
+  /** Obtain the name of the form check javascript method to call.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
+  *@return the name of the form check javascript method.
+  */
+  public String getFormCheckJavascriptMethodName(int connectionSequenceNumber);
+
+  /** Obtain the name of the form presave check javascript method to call.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
+  *@return the name of the form presave check javascript method.
+  */
+  public String getFormPresaveCheckJavascriptMethodName(int connectionSequenceNumber);
+
   /** Output the specification header section.
   * This method is called in the head section of a job page which has selected a repository connection of the
   * current type.  Its purpose is to add the required tabs to the list, and to output any javascript methods
@@ -261,9 +273,11 @@ public interface IRepositoryConnector ex
   *@param out is the output to which any HTML should be sent.
   *@param locale is the locale the output is preferred to be in.
   *@param ds is the current document specification for this job.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
   *@param tabsArray is an array of tab names.  Add to this array any tab names that are specific to the connector.
   */
-  public void outputSpecificationHeader(IHTTPOutput out, Locale locale, DocumentSpecification ds, List<String> tabsArray)
+  public void outputSpecificationHeader(IHTTPOutput out, Locale locale, DocumentSpecification ds,
+    int connectionSequenceNumber, List<String> tabsArray)
     throws ManifoldCFException, IOException;
   
   /** Output the specification body section.
@@ -275,9 +289,13 @@ public interface IRepositoryConnector ex
   *@param out is the output to which any HTML should be sent.
   *@param locale is the locale the output is preferred to be in.
   *@param ds is the current document specification for this job.
-  *@param tabName is the current tab name.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
+  *@param actualSequenceNumber is the connection within the job that has currently been selected.
+  *@param tabName is the current tab name.  (actualSequenceNumber, tabName) form a unique tuple within
+  *  the job.
   */
-  public void outputSpecificationBody(IHTTPOutput out, Locale locale, DocumentSpecification ds, String tabName)
+  public void outputSpecificationBody(IHTTPOutput out, Locale locale, DocumentSpecification ds,
+    int connectionSequenceNumber, int actualSequenceNumber, String tabName)
     throws ManifoldCFException, IOException;
   
   /** Process a specification post.
@@ -288,10 +306,12 @@ public interface IRepositoryConnector ex
   *@param variableContext contains the post data, including binary file-upload information.
   *@param locale is the locale the output is preferred to be in.
   *@param ds is the current document specification for this job.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
   *@return null if all is well, or a string error message if there is an error that should prevent saving of
   * the job (and cause a redirection to an error page).
   */
-  public String processSpecificationPost(IPostParameters variableContext, Locale locale, DocumentSpecification ds)
+  public String processSpecificationPost(IPostParameters variableContext, Locale locale, DocumentSpecification ds,
+    int connectionSequenceNumber)
     throws ManifoldCFException;
   
   /** View specification.
@@ -302,8 +322,11 @@ public interface IRepositoryConnector ex
   *@param out is the output to which any HTML should be sent.
   *@param locale is the locale the output is preferred to be in.
   *@param ds is the current document specification for this job.
+  *@param connectionSequenceNumber is the unique number of this connection within the job.
   */
-  public void viewSpecification(IHTTPOutput out, Locale locale, DocumentSpecification ds)
+  public void viewSpecification(IHTTPOutput out, Locale locale, DocumentSpecification ds,
+    int connectionSequenceNumber)
     throws ManifoldCFException, IOException;
 
+
 }