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 2015/01/05 01:39:43 UTC

svn commit: r1649449 - in /manifoldcf/branches/CONNECTORS-1134: connectors/forcedmetadata/connector/src/main/java/org/apache/manifoldcf/agents/transformation/forcedmetadata/ connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldc...

Author: kwright
Date: Mon Jan  5 00:39:43 2015
New Revision: 1649449

URL: http://svn.apache.org/r1649449
Log:
UI, backwards compatibility changes

Added:
    manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification_Expressions.html   (with props)
Removed:
    manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification_FieldMapping.html
    manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification_ForcedMetadata.html
Modified:
    manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/java/org/apache/manifoldcf/agents/transformation/forcedmetadata/ForcedMetadataConnector.java
    manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_en_US.properties
    manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_ja_JP.properties
    manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_zh_CN.properties
    manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification.js
    manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/viewSpecification.html
    manifoldcf/branches/CONNECTORS-1134/framework/agents/src/main/java/org/apache/manifoldcf/agents/interfaces/RepositoryDocument.java

Modified: manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/java/org/apache/manifoldcf/agents/transformation/forcedmetadata/ForcedMetadataConnector.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/java/org/apache/manifoldcf/agents/transformation/forcedmetadata/ForcedMetadataConnector.java?rev=1649449&r1=1649448&r2=1649449&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/java/org/apache/manifoldcf/agents/transformation/forcedmetadata/ForcedMetadataConnector.java (original)
+++ manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/java/org/apache/manifoldcf/agents/transformation/forcedmetadata/ForcedMetadataConnector.java Mon Jan  5 00:39:43 2015
@@ -34,6 +34,7 @@ public class ForcedMetadataConnector ext
   // Nodes and attributes representing parameters and values.
   // There will be node for every parameter/value pair.
   
+  public static final String NODE_EXPRESSION = "expression";
   public static final String NODE_PAIR = "pair";
   public static final String ATTRIBUTE_PARAMETER = "parameter";
   public static final String NODE_FIELDMAP = "fieldmap";
@@ -47,8 +48,7 @@ public class ForcedMetadataConnector ext
   
   private static final String VIEW_SPEC = "viewSpecification.html";
   private static final String EDIT_SPEC_HEADER = "editSpecification.js";
-  private static final String EDIT_SPEC_FORCED_METADATA = "editSpecification_ForcedMetadata.html";
-  private static final String EDIT_SPEC_FIELDMAPPING = "editSpecification_FieldMapping.html";
+  private static final String EDIT_SPEC_EXPRESSIONS = "editSpecification_Expressions.html";
 
   /** Get a pipeline version string, given a pipeline specification object.  The version string is used to
   * uniquely describe the pertinent details of the specification and the configuration, to allow the Connector 
@@ -93,38 +93,116 @@ public class ForcedMetadataConnector ext
     SpecPacker sp = new SpecPacker(pipelineDescription.getSpecification());
     // We have to create a copy of the Repository Document, since we might be rearranging things
     RepositoryDocument docCopy = document.duplicate();
-    docCopy.clearFields();
-    // Do the mapping first!!
-    Iterator<String> fields = document.getFields();
-    while (fields.hasNext())
-    {
-      String field = fields.next();
-      String target = sp.getMapping(field);
-      if (target != null)
-      {
-        moveData(docCopy,target,document,field,sp.filterEmpty());
-      }
-      else
-      {
-        if (sp.keepAllMetadata())
+    
+    // Clear fields, unless we're supposed to keep what we don't specify
+    if (sp.filterEmpty()) {
+      // We have to process all the fields either way
+      docCopy.clearFields();
+      if (sp.keepAllMetadata()) {
+        // Loop through fields and copy them, filtering empties
+        Iterator<String> fields = document.getFields();
+        while (fields.hasNext())
         {
-          moveData(docCopy,field,document,field,sp.filterEmpty());
+          String field = fields.next();
+          moveData(docCopy,field,document,field,true);
+        }
+      }
+    } else if (!sp.keepAllMetadata()) {
+      // Just chuck all fields so we can start fresh
+      docCopy.clearFields();
+    }
+    
+    // Iterate through the expressions
+    Iterator<String> expressionKeys = sp.getExpressionKeys();
+    while (expressionKeys.hasNext()) {
+      String expressionKey = expressionKeys.next();
+      // Get the set of expressions for the key
+      Set<String> values = sp.getExpressionValues(expressionKey);
+      IDataSource[] dataSources = new IDataSource[values.size()];
+      int k = 0;
+      for (String expression : values) {
+        dataSources[k++] = processExpression(expression, document);
+      }
+      int totalSize = 0;
+      for (IDataSource dataSource : dataSources) {
+        if (dataSource != null)
+          totalSize += dataSource.getSize();
+      }
+      if (totalSize == 0) {
+        docCopy.removeField(expressionKey);
+      } else {
+        // Each IDataSource will contribute zero or more results to the final array.  But here's the tricky part:
+        // the results all must be of the same type.  If there are any differences, then we have to bash them all to
+        // strings first.
+        Object[] allValues;
+        k = 0;
+        if (allDates(dataSources)) {
+          allValues = new Date[totalSize];
+          for (IDataSource dataSource : dataSources) {
+            if (dataSource != null) {
+              for (Object o : dataSource.getRawForm()) {
+                allValues[k++] = o;
+              }
+            }
+          }
+          docCopy.addField(expressionKey,(Date[])conditionallyRemoveNulls(allValues,sp.filterEmpty()));
+        } else if (allReaders(dataSources)) {
+          if (sp.filterEmpty())
+            allValues = new String[totalSize];
+          else
+            allValues = new Reader[totalSize];
+          for (IDataSource dataSource : dataSources) {
+            if (dataSource != null) {
+              Object[] sources = sp.filterEmpty()?dataSource.getStringForm():dataSource.getRawForm();
+              for (Object o : sources) {
+                allValues[k++] = o;
+              }
+            }
+          }
+          if (sp.filterEmpty())
+            docCopy.addField(expressionKey,removeEmpties((String[])allValues));
+          else
+            docCopy.addField(expressionKey,(Reader[])allValues);
+        } else {
+          allValues = new String[totalSize];
+          // Convert to strings throughout
+          for (IDataSource dataSource : dataSources) {
+            if (dataSource != null) {
+              for (Object o : dataSource.getStringForm()) {
+                allValues[k++] = o;
+              }
+            }
+          }
+          if (sp.filterEmpty())
+            docCopy.addField(expressionKey,removeEmpties((String[])allValues));
+          else
+            docCopy.addField(expressionKey,(String[])allValues);
         }
       }
     }
-
-    Iterator<String> keys = sp.getParameterKeys();
-    while (keys.hasNext())
-    {
-      String key = keys.next();
-      docCopy.addField(key,sp.getParameterValues(key));
-    }
+    
     // Finally, send the modified repository document onward to the next pipeline stage.
     // If we'd done anything to the stream, we'd have needed to create a new RepositoryDocument object and copied the
     // data into it, and closed the new stream after sendDocument() was called.
     return activities.sendDocument(documentURI,docCopy);
   }
 
+  protected static boolean allDates(IDataSource[] dataSources) {
+    for (IDataSource ds : dataSources) {
+      if (ds != null && !(ds.getRawForm() instanceof Date[]))
+        return false;
+    }
+    return true;
+  }
+
+  protected static boolean allReaders(IDataSource[] dataSources) {
+    for (IDataSource ds : dataSources) {
+      if (ds != null && !(ds.getRawForm() instanceof Reader[]))
+        return false;
+    }
+    return true;
+  }
+  
   protected static void moveData(RepositoryDocument docCopy, String target, RepositoryDocument document, String field, boolean filterEmpty)
     throws ManifoldCFException, IOException
   {
@@ -240,9 +318,7 @@ public class ForcedMetadataConnector ext
   {
     // Output specification header
     
-    // Add Forced Metadata to tab array
-    tabsArray.add(Messages.getString(locale, "ForcedMetadata.FieldMappingTabName"));
-    tabsArray.add(Messages.getString(locale, "ForcedMetadata.ForcedMetadata"));
+    tabsArray.add(Messages.getString(locale, "ForcedMetadata.Expressions"));
 
     Map<String, Object> paramMap = new HashMap<String, Object>();
     paramMap.put("SEQNUM",Integer.toString(connectionSequenceNumber));
@@ -272,11 +348,9 @@ public class ForcedMetadataConnector ext
     paramMap.put("SEQNUM",Integer.toString(connectionSequenceNumber));
     paramMap.put("SELECTEDNUM",Integer.toString(actualSequenceNumber));
 
-    fillInForcedMetadataTab(paramMap, os);
-    fillInFieldMappingSpecificationMap(paramMap, os);
+    fillInExpressionsTab(paramMap, os);
 
-    Messages.outputResourceWithVelocity(out,locale,EDIT_SPEC_FORCED_METADATA,paramMap);
-    Messages.outputResourceWithVelocity(out,locale,EDIT_SPEC_FIELDMAPPING,paramMap);
+    Messages.outputResourceWithVelocity(out,locale,EDIT_SPEC_EXPRESSIONS,paramMap);
   }
   
   /** Process a specification post.
@@ -296,96 +370,53 @@ public class ForcedMetadataConnector ext
   {
     // Process specification post
     String seqPrefix = "s"+connectionSequenceNumber+"_";
-    String forcedCount = variableContext.getParameter(seqPrefix+"forcedmetadata_count");
-    if (forcedCount != null)
+    String expressionCount = variableContext.getParameter(seqPrefix+"expression_count");
+    if (expressionCount != null)
     {
-      int count = Integer.parseInt(forcedCount);
-      // Delete old spec data
+      int count = Integer.parseInt(expressionCount);
+      // Delete old spec data, including legacy node types we no longer use
       int i = 0;
       while (i < os.getChildCount())
       {
         SpecificationNode cn = os.getChild(i);
-        if (cn.getType().equals(NODE_PAIR))
+        if (cn.getType().equals(NODE_EXPRESSION) || cn.getType().equals(NODE_PAIR) || cn.getType().equals(NODE_FIELDMAP))
           os.removeChild(i);
         else
           i++;
       }
+
       // Now, go through form data
       for (int j = 0; j < count; j++)
       {
-        String op = variableContext.getParameter(seqPrefix+"forcedmetadata_"+j+"_op");
+        String op = variableContext.getParameter(seqPrefix+"expression_"+j+"_op");
         if (op != null && op.equals("Delete"))
           continue;
-        String paramName = variableContext.getParameter(seqPrefix+"forcedmetadata_"+j+"_name");
-        String paramValue = variableContext.getParameter(seqPrefix+"forcedmetadata_"+j+"_value");
-        SpecificationNode sn = new SpecificationNode(NODE_PAIR);
+        String paramName = variableContext.getParameter(seqPrefix+"expression_"+j+"_name");
+        String paramRemove = variableContext.getParameter(seqPrefix+"expression_"+j+"_remove");
+        String paramValue = variableContext.getParameter(seqPrefix+"expression_"+j+"_value");
+        SpecificationNode sn = new SpecificationNode(NODE_EXPRESSION);
         sn.setAttribute(ATTRIBUTE_PARAMETER,paramName);
-        sn.setAttribute(ATTRIBUTE_VALUE,paramValue);
+        if (!(paramRemove != null && paramRemove.equals("true")))
+          sn.setAttribute(ATTRIBUTE_VALUE,paramValue);
         os.addChild(os.getChildCount(),sn);
       }
       // Look for add operation
-      String addOp = variableContext.getParameter(seqPrefix+"forcedmetadata_op");
+      String addOp = variableContext.getParameter(seqPrefix+"expression_op");
       if (addOp != null && addOp.equals("Add"))
       {
-        String paramName = variableContext.getParameter(seqPrefix+"forcedmetadata_name");
-        String paramValue = variableContext.getParameter(seqPrefix+"forcedmetadata_value");
-        SpecificationNode sn = new SpecificationNode(NODE_PAIR);
+        String paramName = variableContext.getParameter(seqPrefix+"expression_name");
+        String paramRemove = variableContext.getParameter(seqPrefix+"expression_remove");
+        String paramValue = variableContext.getParameter(seqPrefix+"expression_value");
+        SpecificationNode sn = new SpecificationNode(NODE_EXPRESSION);
         sn.setAttribute(ATTRIBUTE_PARAMETER,paramName);
-        sn.setAttribute(ATTRIBUTE_VALUE,paramValue);
+        if (!(paramRemove != null && paramRemove.equals("true")))
+          sn.setAttribute(ATTRIBUTE_VALUE,paramValue);
         os.addChild(os.getChildCount(),sn);
       }
+
     }
     
-    String x = variableContext.getParameter(seqPrefix+"fieldmapping_count");
-    if (x != null && x.length() > 0)
-    {
-      // About to gather the fieldmapping nodes, so get rid of the old ones.
-      int i = 0;
-      while (i < os.getChildCount())
-      {
-        SpecificationNode node = os.getChild(i);
-        if (node.getType().equals(NODE_FIELDMAP) || node.getType().equals(NODE_KEEPMETADATA))
-          os.removeChild(i);
-        else
-          i++;
-      }
-      int count = Integer.parseInt(x);
-      i = 0;
-      while (i < count)
-      {
-        String prefix = seqPrefix+"fieldmapping_";
-        String suffix = "_"+Integer.toString(i);
-        String op = variableContext.getParameter(prefix+"op"+suffix);
-        if (op == null || !op.equals("Delete"))
-        {
-          // Gather the fieldmap etc.
-          String source = variableContext.getParameter(prefix+"source"+suffix);
-          String target = variableContext.getParameter(prefix+"target"+suffix);
-          if (target == null)
-            target = "";
-          SpecificationNode node = new SpecificationNode(NODE_FIELDMAP);
-          node.setAttribute(ATTRIBUTE_SOURCE,source);
-          node.setAttribute(ATTRIBUTE_TARGET,target);
-          os.addChild(os.getChildCount(),node);
-        }
-        i++;
-      }
-      
-      String addop = variableContext.getParameter(seqPrefix+"fieldmapping_op");
-      if (addop != null && addop.equals("Add"))
-      {
-        String source = variableContext.getParameter(seqPrefix+"fieldmapping_source");
-        String target = variableContext.getParameter(seqPrefix+"fieldmapping_target");
-        if (target == null)
-          target = "";
-        SpecificationNode node = new SpecificationNode(NODE_FIELDMAP);
-        node.setAttribute(ATTRIBUTE_SOURCE,source);
-        node.setAttribute(ATTRIBUTE_TARGET,target);
-        os.addChild(os.getChildCount(),node);
-      }
-    }
-    
-    x = variableContext.getParameter(seqPrefix+"keepallmetadata_present");
+    String x = variableContext.getParameter(seqPrefix+"keepallmetadata_present");
     if (x != null && x.length() > 0)
     {
       String keepAll = variableContext.getParameter(seqPrefix+"keepallmetadata");
@@ -454,16 +485,17 @@ public class ForcedMetadataConnector ext
     paramMap.put("SEQNUM",Integer.toString(connectionSequenceNumber));
     
     // Fill in the map with data from all tabs
-    fillInForcedMetadataTab(paramMap, os);
-    fillInFieldMappingSpecificationMap(paramMap, os);
+    fillInExpressionsTab(paramMap, os);
 
     Messages.outputResourceWithVelocity(out,locale,VIEW_SPEC,paramMap);
   }
 
-  protected static void fillInFieldMappingSpecificationMap(Map<String,Object> paramMap, Specification os)
+  protected static void fillInExpressionsTab(Map<String,Object> paramMap, Specification os)
   {
-    // Prep for field mappings
-    List<Map<String,String>> fieldMappings = new ArrayList<Map<String,String>>();
+    final Map<String,Set<String>> expressions = new HashMap<String,Set<String>>();
+    final Map<String,Set<String>> expressionAdditions = new HashMap<String,Set<String>>();
+    final Map<String,Set<String>> additions = new HashMap<String,Set<String>>();
+    
     String keepAllMetadataValue = "true";
     String filterEmptyValue = "true";
     for (int i = 0; i < os.getChildCount(); i++)
@@ -473,18 +505,44 @@ public class ForcedMetadataConnector ext
         String source = sn.getAttributeValue(ATTRIBUTE_SOURCE);
         String target = sn.getAttributeValue(ATTRIBUTE_TARGET);
         String targetDisplay;
-        if (target == null)
+        
+        expressions.put(source,new HashSet<String>());
+        if (target != null)
         {
-          target = "";
-          targetDisplay = "(remove)";
+          Set<String> sources = new HashSet<String>();
+          sources.add("${"+source+"}");
+          expressions.put(target,sources);
+        }
+      }
+      else if (sn.getType().equals(NODE_PAIR))
+      {
+        String parameter = sn.getAttributeValue(ATTRIBUTE_PARAMETER);
+        String value = sn.getAttributeValue(ATTRIBUTE_VALUE);
+        // Since the same target is completely superceded by a NODE_PAIR, but NODE_PAIRs
+        // are cumulative, I have to build these completely and then post-process them.
+        Set<String> addition = additions.get(parameter);
+        if (addition == null)
+        {
+          addition = new HashSet<String>();
+          additions.put(parameter,addition);
+        }
+        addition.add(expressionEscape(value));
+      }
+      else if (sn.getType().equals(NODE_EXPRESSION))
+      {
+        String parameter = sn.getAttributeValue(ATTRIBUTE_PARAMETER);
+        String value = sn.getAttributeValue(ATTRIBUTE_VALUE);
+        if (value == null) {
+          expressionAdditions.put(parameter,new HashSet<String>());
+        } else {
+          Set<String> expressionAddition = expressionAdditions.get(parameter);
+          if (expressionAddition == null)
+          {
+            expressionAddition = new HashSet<String>();
+            expressionAdditions.put(parameter,expressionAddition);
+          }
+          expressionAddition.add(value);
         }
-        else
-          targetDisplay = target;
-        Map<String,String> fieldMapping = new HashMap<String,String>();
-        fieldMapping.put("SOURCE",source);
-        fieldMapping.put("TARGET",target);
-        fieldMapping.put("TARGETDISPLAY",targetDisplay);
-        fieldMappings.add(fieldMapping);
       }
       else if (sn.getType().equals(NODE_KEEPMETADATA))
       {
@@ -495,77 +553,191 @@ public class ForcedMetadataConnector ext
         filterEmptyValue = sn.getAttributeValue(ATTRIBUTE_VALUE);
       }
     }
-    paramMap.put("FIELDMAPPINGS",fieldMappings);
-    paramMap.put("KEEPALLMETADATA",keepAllMetadataValue);
-    paramMap.put("FILTEREMPTY",filterEmptyValue);
-  }
-
-  protected static void fillInForcedMetadataTab(Map<String,Object> paramMap, Specification os)
-  {
-    // First, sort everything
-    Map<String,Set<String>> params = new HashMap<String,Set<String>>();
-    for (int i = 0; i < os.getChildCount(); i++)
+    
+    // Postprocessing.
+    // Override the moves with the additions
+    for (String parameter : additions.keySet())
     {
-      SpecificationNode sn = os.getChild(i);
-      if (sn.getType().equals(NODE_PAIR))
-      {
-        String parameter = sn.getAttributeValue(ATTRIBUTE_PARAMETER);
-        String value = sn.getAttributeValue(ATTRIBUTE_VALUE);
-        Set<String> values = params.get(parameter);
-        if (values == null)
-        {
-          values = new HashSet<String>();
-          params.put(parameter,values);
-        }
-        values.add(value);
-      }
+      expressions.put(parameter,additions.get(parameter));
     }
-    
-    // We construct a list of maps from the parameters
-    List<Map<String,String>> pObject = new ArrayList<Map<String,String>>();
 
-    String[] keys = new String[params.size()];
-    int j = 0;
-    for (String key : params.keySet())
+    // Override all with expression additions
+    for (String parameter : expressionAdditions.keySet())
     {
-      keys[j++] = key;
+      expressions.put(parameter,expressionAdditions.get(parameter));
     }
+
+    // Problem: how to display case where we want a null source??
+    // A: Special value
+    List<Map<String,String>> pObject = new ArrayList<Map<String,String>>();
+    String[] keys = expressions.keySet().toArray(new String[0]);
     java.util.Arrays.sort(keys);
     
     // Now, build map
     for (String key : keys)
     {
-      Set<String> values = params.get(key);
-      String[] valueArray = new String[values.size()];
-      j = 0;
-      for (String value : values)
-      {
-        valueArray[j++] = value;
-      }
-      java.util.Arrays.sort(valueArray);
-      
-      for (String value : valueArray)
-      {
+      Set<String> values = expressions.get(key);
+      if (values.size() == 0) {
         Map<String,String> record = new HashMap<String,String>();
         record.put("parameter",key);
-        record.put("value",value);
+        record.put("value","");
+        record.put("isnull","true");
         pObject.add(record);
+      } else {
+        String[] valueArray = values.toArray(new String[0]);
+        java.util.Arrays.sort(valueArray);
+        
+        for (String value : valueArray)
+        {
+          Map<String,String> record = new HashMap<String,String>();
+          record.put("parameter",key);
+          record.put("value",value);
+          record.put("isnull","false");
+          pObject.add(record);
+        }
       }
     }
     
-    paramMap.put("PARAMETERS",pObject);
+    paramMap.put("EXPRESSIONS",pObject);
+    paramMap.put("KEEPALLMETADATA",keepAllMetadataValue);
+    paramMap.put("FILTEREMPTY",filterEmptyValue);
+  }
+  
+  protected static String expressionEscape(String input) {
+    // Not doing any escaping yet
+    return input;
   }
 
+  protected static String expressionUnescape(String input) {
+    // Not doing any escaping yet
+    return input;
+  }
+  
+  protected interface IDataSource {
+    public int getSize();
+    public Object[] getRawForm();
+    public String[] getStringForm() throws IOException;
+  }
+  
+  protected static class StringSource implements IDataSource {
+    protected final String[] data;
+    
+    public StringSource(String data) {
+      this.data = new String[]{data};
+    }
+    
+    public StringSource(String[] data) {
+      this.data = data;
+    }
+    
+    @Override
+    public int getSize() {
+      return data.length;
+    }
+    
+    @Override
+    public Object[] getRawForm() {
+      return data;
+    }
+    
+    @Override
+    public String[] getStringForm() {
+      return data;
+    }
+  }
+  
+  protected static class FieldSource implements IDataSource {
+    
+    protected final RepositoryDocument rd;
+    protected final String fieldName;
+    
+    public FieldSource(RepositoryDocument rd, String fieldName) {
+      this.rd = rd;
+      this.fieldName = fieldName;
+    }
+    
+    @Override
+    public int getSize() {
+      Object[] rawForm = getRawForm();
+      if (rawForm == null)
+        return 0;
+      return rawForm.length;
+    }
+    
+    @Override
+    public Object[] getRawForm() {
+      return rd.getField(fieldName);
+    }
+    
+    @Override
+    public String[] getStringForm()
+      throws IOException {
+      return rd.getFieldAsStrings(fieldName);
+    }
+  }
+  
+  protected static IDataSource append(IDataSource currentValues, IDataSource data)
+    throws IOException {
+    // currentValues and data can either be:
+    // Date[], String[], or Reader[].
+    // We want to preserve the type in as high a form as possible when we compute the combinations.
+    if (currentValues == null)
+      return data;
+    if (currentValues.getSize() == 0)
+      return currentValues;
+    // Any combination causes conversion to a string, so if we get here, we can read the inputs all
+    // as strings safely.
+    String[] currentStrings = currentValues.getStringForm();
+    String[] dataStrings = data.getStringForm();
+    String[] rval = new String[currentStrings.length * dataStrings.length];
+    int rvalIndex = 0;
+    for (String currentString : currentStrings) {
+      for (String dataString : dataStrings) {
+        rval[rvalIndex++] = currentString + dataString;
+      }
+    }
+    return new StringSource(rval);
+  }
+  
+  protected static IDataSource processExpression(String expression, RepositoryDocument sourceDocument)
+    throws IOException {
+    int index = 0;
+    IDataSource input = null;
+    while (true) {
+      // If we're at the end, return the input
+      if (index == expression.length())
+        return input;
+      // Look for next field specification
+      int field = expression.indexOf("${",index);
+      if (field == -1)
+        return append(input, new StringSource(expressionUnescape(expression.substring(index))));
+      if (field > 0)
+        input = append(input, new StringSource(expressionUnescape(expression.substring(index,field))));
+      // Get the field name
+      int fieldEnd = expression.indexOf("}",field);
+      String fieldName;
+      if (fieldEnd == -1) {
+        fieldName = expression.substring(field+2);
+        return append(input, new FieldSource(sourceDocument, fieldName));
+      } else {
+        fieldName = expression.substring(field+2,fieldEnd);
+        input = append(input, new FieldSource(sourceDocument, fieldName));
+        index = fieldEnd+1;
+      }
+    }
+  }
+  
   protected static class SpecPacker {
     
-    private final Map<String,String> sourceTargets = new HashMap<String,String>();
     private final boolean keepAllMetadata;
     private final boolean filterEmpty;
-    private final Map<String,Set<String>> parameters = new HashMap<String,Set<String>>();
+    private final Map<String,Set<String>> expressions = new HashMap<String,Set<String>>();
 
     public SpecPacker(Specification os) {
       boolean keepAllMetadata = true;
       boolean filterEmpty = true;
+      final Map<String,Set<String>> additions = new HashMap<String,Set<String>>();
+      final Map<String,Set<String>> expressionAdditions = new HashMap<String,Set<String>>();
       for (int i = 0; i < os.getChildCount(); i++) {
         SpecificationNode sn = os.getChild(i);
         
@@ -579,24 +751,58 @@ public class ForcedMetadataConnector ext
           String source = sn.getAttributeValue(ATTRIBUTE_SOURCE);
           String target = sn.getAttributeValue(ATTRIBUTE_TARGET);
           
-          if (target == null) {
-            target = "";
+          expressions.put(source,new HashSet<String>());
+          // Null target means to remove the *source* from the document.
+          if (target != null) {
+            Set<String> sources = new HashSet<String>();
+            sources.add("${"+source+"}");
+            expressions.put(target,sources);
           }
-          sourceTargets.put(source, target);
         }
         else if (sn.getType().equals(NODE_PAIR))
         {
           String parameter = sn.getAttributeValue(ATTRIBUTE_PARAMETER);
           String value = sn.getAttributeValue(ATTRIBUTE_VALUE);
-          Set<String> params = parameters.get(parameter);
-          if (params == null)
+          // Since the same target is completely superceded by a NODE_PAIR, but NODE_PAIRs
+          // are cumulative, I have to build these completely and then post-process them.
+          Set<String> addition = additions.get(parameter);
+          if (addition == null)
           {
-            params = new HashSet<String>();
-            parameters.put(parameter,params);
+            addition = new HashSet<String>();
+            additions.put(parameter,addition);
           }
-          params.add(value);
+          addition.add(expressionEscape(value));
         }
+        else if (sn.getType().equals(NODE_EXPRESSION))
+        {
+          String parameter = sn.getAttributeValue(ATTRIBUTE_PARAMETER);
+          String value = sn.getAttributeValue(ATTRIBUTE_VALUE);
+          if (value == null) {
+            expressionAdditions.put(parameter,new HashSet<String>());
+          } else {
+            Set<String> expressionAddition = expressionAdditions.get(parameter);
+            if (expressionAddition == null)
+            {
+              expressionAddition = new HashSet<String>();
+              expressionAdditions.put(parameter,expressionAddition);
+            }
+            expressionAddition.add(value);
+          }
+        }
+      }
+      
+      // Override the moves with the additions
+      for (String parameter : additions.keySet())
+      {
+        expressions.put(parameter,additions.get(parameter));
+      }
+
+      // Override all with expression additions
+      for (String parameter : expressionAdditions.keySet())
+      {
+        expressions.put(parameter,expressionAdditions.get(parameter));
       }
+      
       this.keepAllMetadata = keepAllMetadata;
       this.filterEmpty = filterEmpty;
     }
@@ -605,25 +811,16 @@ public class ForcedMetadataConnector ext
       StringBuilder sb = new StringBuilder();
       int i;
       
-      // Mappings
-      final String[] sortArray = new String[sourceTargets.size()];
-      i = 0;
-      for (String source : sourceTargets.keySet()) {
-        sortArray[i++] = source;
-      }
+      final String[] sortArray = expressions.keySet().toArray(new String[0]);
       java.util.Arrays.sort(sortArray);
-      
-      List<String> packedMappings = new ArrayList<String>();
-      String[] fixedList = new String[2];
-      for (String source : sortArray) {
-        String target = sourceTargets.get(source);
-        StringBuilder localBuffer = new StringBuilder();
-        fixedList[0] = source;
-        fixedList[1] = target;
-        packFixedList(localBuffer,fixedList,':');
-        packedMappings.add(localBuffer.toString());
+      // Pack the list of keys
+      packList(sb,sortArray,'+');
+      for (String key : sortArray) {
+        Set<String> values = expressions.get(key);
+        String[] valueArray = values.toArray(new String[0]);
+        java.util.Arrays.sort(valueArray);
+        packList(sb,valueArray,'+');
       }
-      packList(sb,packedMappings,'+');
 
       // Keep all metadata
       if (keepAllMetadata)
@@ -631,30 +828,6 @@ public class ForcedMetadataConnector ext
       else
         sb.append('-');
       
-      // Get the keys and sort them
-      final String[] keys = new String[parameters.size()];
-      int j = 0;
-      for (String key : parameters.keySet())
-      {
-        keys[j++] = key;
-      }
-      java.util.Arrays.sort(keys);
-      // Pack the list of keys
-      packList(sb,keys,'+');
-      // Now, go through each key and individually pack the values
-      for (String key : keys)
-      {
-        Set<String> values = parameters.get(key);
-        String[] valueArray = new String[values.size()];
-        j = 0;
-        for (String value : values)
-        {
-          valueArray[j++] = value;
-        }
-        java.util.Arrays.sort(valueArray);
-        packList(sb,valueArray,'+');
-      }
-
       // Filter empty
       if (filterEmpty)
         sb.append('+');
@@ -664,8 +837,14 @@ public class ForcedMetadataConnector ext
       return sb.toString();
     }
     
-    public String getMapping(String source) {
-      return sourceTargets.get(source);
+    public Iterator<String> getExpressionKeys()
+    {
+      return expressions.keySet().iterator();
+    }
+    
+    public Set<String> getExpressionValues(String key)
+    {
+      return expressions.get(key);
     }
     
     public boolean keepAllMetadata() {
@@ -675,27 +854,7 @@ public class ForcedMetadataConnector ext
     public boolean filterEmpty() {
       return filterEmpty;
     }
-    
-    public Iterator<String> getParameterKeys()
-    {
-      return parameters.keySet().iterator();
-    }
-    
-    public String[] getParameterValues(String key)
-    {
-      Set<String> values = parameters.get(key);
-      if (values == null)
-        return null;
-      String[] rval = new String[values.size()];
-      int i = 0;
-      for (String value : values)
-      {
-        rval[i++] = value;
-      }
-      return rval;
-    }
   }
-
 }
 
 

Modified: manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_en_US.properties
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_en_US.properties?rev=1649449&r1=1649448&r2=1649449&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_en_US.properties (original)
+++ manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_en_US.properties Mon Jan  5 00:39:43 2015
@@ -16,6 +16,17 @@
 ForcedMetadata.ForcedMetadata=Add metadata
 ForcedMetadata.FieldMappingTabName=Move metadata
 
+ForcedMetadata.Expressions=Metadata expressions
+ForcedMetadata.RemoveQ=Remove?
+ForcedMetadata.ParameterValueExpression=Parameter value expression
+ForcedMetadata.MetadataExpressionsColon=Metadata expressions:
+ForcedMetadata.NoExpressionsSpecified=No expressions provided
+ForcedMetadata.Deleteexpressionnumber=Delete expression #
+ForcedMetadata.Addexpression=Add expression
+ForcedMetadata.True=true
+ForcedMetadata.False=false
+ForcedMetadata.ExpressionMetadataNameMustNotBeNull=Expression metadata name must not be null
+
 ForcedMetadata.ForcedMetadataNameMustNotBeNull=Added metadata name must not be null
 ForcedMetadata.ForcedMetadataColon=Added metadata:
 ForcedMetadata.ParameterName=Parameter name

Modified: manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_ja_JP.properties
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_ja_JP.properties?rev=1649449&r1=1649448&r2=1649449&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_ja_JP.properties (original)
+++ manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_ja_JP.properties Mon Jan  5 00:39:43 2015
@@ -16,6 +16,17 @@
 ForcedMetadata.ForcedMetadata=強制メタデータ
 ForcedMetadata.FieldMappingTabName=フィールドマッピング
 
+ForcedMetadata.Expressions=Metadata expressions
+ForcedMetadata.RemoveQ=Remove?
+ForcedMetadata.ParameterValueExpression=Parameter value expression
+ForcedMetadata.MetadataExpressionsColon=Metadata expressions:
+ForcedMetadata.NoExpressionsSpecified=No expressions provided
+ForcedMetadata.Deleteexpressionnumber=Delete expression #
+ForcedMetadata.Addexpression=Add expression
+ForcedMetadata.True=true
+ForcedMetadata.False=false
+ForcedMetadata.ExpressionMetadataNameMustNotBeNull=Expression metadata name must not be null
+
 ForcedMetadata.ForcedMetadataNameMustNotBeNull=強制メタデータ名を必ず入力してください
 ForcedMetadata.ForcedMetadataColon=強制メタデータ:
 ForcedMetadata.ParameterName=パラメータ名

Modified: manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_zh_CN.properties
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_zh_CN.properties?rev=1649449&r1=1649448&r2=1649449&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_zh_CN.properties (original)
+++ manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/native2ascii/org/apache/manifoldcf/agents/transformation/forcedmetadata/common_zh_CN.properties Mon Jan  5 00:39:43 2015
@@ -16,6 +16,17 @@
 ForcedMetadata.ForcedMetadata=强制性元数据
 ForcedMetadata.FieldMappingTabName=字段映射
 
+ForcedMetadata.Expressions=Metadata expressions
+ForcedMetadata.RemoveQ=Remove?
+ForcedMetadata.ParameterValueExpression=Parameter value expression
+ForcedMetadata.MetadataExpressionsColon=Metadata expressions:
+ForcedMetadata.NoExpressionsSpecified=No expressions provided
+ForcedMetadata.Deleteexpressionnumber=Delete expression #
+ForcedMetadata.Addexpression=Add expression
+ForcedMetadata.True=true
+ForcedMetadata.False=false
+ForcedMetadata.ExpressionMetadataNameMustNotBeNull=Expression metadata name must not be null
+
 ForcedMetadata.ForcedMetadataNameMustNotBeNull=强制性元数据名不能为空
 ForcedMetadata.ForcedMetadataColon=强制性元数据:
 ForcedMetadata.ParameterName=参数名

Modified: manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification.js
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification.js?rev=1649449&r1=1649448&r2=1649449&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification.js (original)
+++ manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification.js Mon Jan  5 00:39:43 2015
@@ -18,6 +18,27 @@
 <script type="text/javascript">
 <!--
 
+function s${SEQNUM}_AddExpression()
+{
+  if (editjob.s${SEQNUM}_expression_name.value == "")
+  {
+    alert("$Encoder.bodyJavascriptEscape($ResourceBundle.getString('ForcedMetadata.ExpressionMetadataNameMustNotBeNull'))");
+    editjob.s${SEQNUM}_expression_name.focus();
+    return;
+  }
+  document.editjob.s${SEQNUM}_expression_op.value="Add";
+  postFormSetAnchor("s${SEQNUM}_expression_tag");
+}
+	
+function s${SEQNUM}_DeleteExpression(n)
+{
+  eval("document.editjob.s${SEQNUM}_expression_"+n+"_op.value = 'Delete'");
+  if (n == 0)
+    postFormSetAnchor("s${SEQNUM}_expression_tag");
+  else
+    postFormSetAnchor("s${SEQNUM}_expression_"+(n-1)+"_tag");
+}
+
 function s${SEQNUM}_AddForcedMetadata()
 {
   if (editjob.s${SEQNUM}_forcedmetadata_name.value == "")

Added: manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification_Expressions.html
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification_Expressions.html?rev=1649449&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification_Expressions.html (added)
+++ manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification_Expressions.html Mon Jan  5 00:39:43 2015
@@ -0,0 +1,108 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+#if($TABNAME == $ResourceBundle.getString('ForcedMetadata.Expressions') && $SEQNUM == $SELECTEDNUM)
+
+<table class="displaytable">
+  <tr>
+    <td class="separator" colspan="4"><hr/></td>
+  </tr>
+  <tr>
+    <td class="description" colspan="1"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.MetadataExpressionsColon'))</nobr></td>
+    <td class="boxcell" colspan="3">
+      <table class="formtable">
+        <tr class="formheaderrow">
+          <td class="formcolumnheader"></td>
+          <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.ParameterName'))</nobr></td>
+          <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.RemoveQ'))</nobr></td>
+          <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.ParameterValueExpression'))</nobr></td>
+        </tr>
+  #set($paramcounter = 0)
+  #foreach($paramrecord in $EXPRESSIONS)
+    #if(($paramcounter % 2) == 0)
+        <tr class="evenformrow">
+    #else
+        <tr class="oddformrow">
+    #end
+          <td class="formcolumncell">
+            <a name="s${SEQNUM}_forcedmetadata_${paramcounter}_tag"/>
+            <input type="button" value="$Encoder.attributeEscape($ResourceBundle.getString('ForcedMetadata.Delete'))" alt="$Encoder.attributeEscape($ResourceBundle.getString('ForcedMetadata.Deleteexpressionnumber'))${paramcounter}" onclick='javascript:s${SEQNUM}_DeleteExpression(${paramcounter});'/>
+            <input type="hidden" name="s${SEQNUM}_expression_${paramcounter}_op" value="Continue"/>
+            <input type="hidden" name="s${SEQNUM}_expression_${paramcounter}_name" value="$Encoder.attributeEscape($paramrecord.get('parameter'))"/>
+            <input type="hidden" name="s${SEQNUM}_expression_${paramcounter}_remove" value="$Encoder.attributeEscape($paramrecord.get('isnull'))"/>
+            <input type="hidden" name="s${SEQNUM}_expression_${paramcounter}_value" value="$Encoder.attributeEscape($paramrecord.get('value'))"/>
+          </td>
+          <td class="formcolumncell">
+            <nobr>$Encoder.bodyEscape($paramrecord.get('parameter'))</nobr>
+          </td>
+          <td class="formcolumncell">
+            <nobr>
+    #if($paramrecord.get('isnull') == 'true')
+              $Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.True'))
+    #end
+    #if($paramrecord.get('isnull') == 'false')
+              $Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.False'))
+    #end
+            </nobr>
+          </td>
+          <td class="formcolumncell">
+            <nobr>$Encoder.bodyEscape($paramrecord.get('value'))</nobr>
+          </td>
+        </tr>
+    #set($paramcounter = $paramcounter + 1)
+  #end
+  #if($paramcounter == 0)
+        <tr class="formrow"><td colspan="3" class="formcolumnmessage"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.NoExpressionsSpecified'))</nobr></td></tr>
+  #end
+        <tr class="formrow"><td colspan="3" class="formseparator"><hr/></td></tr>
+        <tr class="formrow">
+          <td class="formcolumncell">
+            <a name="s${SEQNUM}_expression_tag"/>
+            <input type="hidden" name="s${SEQNUM}_expression_op" value="Continue"/>
+            <input type="button" value="$Encoder.attributeEscape($ResourceBundle.getString('ForcedMetadata.Add'))" alt="$Encoder.attributeEscape($ResourceBundle.getString('ForcedMetadata.Addexpression'))" onclick="javascript:s${SEQNUM}_AddExpression();"/>
+            <input type="hidden" name="s${SEQNUM}_expression_count" value="${paramcounter}"/>
+          </td>
+          <td class="formcolumncell">
+            <input type="text" name="s${SEQNUM}_expression_name" size="30" value=""/>
+          </td>
+          <td class="formcolumncell">
+            <select name="s${SEQNUM}_expression_remove" size="2"/>
+              <option name="true">$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.True'))</option>
+              <option name="false">$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.False'))</option>
+            </select>
+          </td>
+          <td class="formcolumncell">
+            <input type="text" name="s${SEQNUM}_expression_value" size="30" value=""/>
+          </td>
+        </tr>
+      </table>
+    </td>
+  </tr>
+</table>
+
+#else
+
+  #set($paramcounter = 0)
+  #foreach($paramrecord in $EXPRESSIONS)
+<input type="hidden" name="s${SEQNUM}_expression_${paramcounter}_name" value="$Encoder.attributeEscape($paramrecord.get('parameter'))" />
+<input type="hidden" name="s${SEQNUM}_expression_${paramcounter}_remove" value="$Encoder.attributeEscape($paramrecord.get('isnull'))" />
+<input type="hidden" name="s${SEQNUM}_expression_${paramcounter}_value" value="$Encoder.attributeEscape($paramrecord.get('value'))" />
+    #set($paramcounter = $paramcounter + 1)
+  #end
+<input type="hidden" name="s${SEQNUM}_expression_count" value="${paramcounter}"/>
+
+#end

Propchange: manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification_Expressions.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/editSpecification_Expressions.html
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/viewSpecification.html
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/viewSpecification.html?rev=1649449&r1=1649448&r2=1649449&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/viewSpecification.html (original)
+++ manifoldcf/branches/CONNECTORS-1134/connectors/forcedmetadata/connector/src/main/resources/org/apache/manifoldcf/agents/transformation/forcedmetadata/viewSpecification.html Mon Jan  5 00:39:43 2015
@@ -17,58 +17,16 @@
 
 <table class="displaytable">
   <tr>
-    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.FieldMappings'))</nobr></td>
-    <td class="boxcell">
-      <table class="formtable">
-        <tr class="formheaderrow">
-          <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.MetadataFieldName'))</nobr></td>
-          <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.FinalFieldName'))</nobr></td>
-        </tr>
-#set($fieldcounter = 0)
-#foreach($fieldmapping in $FIELDMAPPINGS)
-  #if(($fieldcounter % 2) == 0)
-        <tr class="evenformrow">
-  #else
-        <tr class="oddformrow">
-  #end
-          <td class="formcolumncell">
-            <nobr>$Encoder.bodyEscape($fieldmapping.get('SOURCE'))</nobr>
-          </td>
-          <td class="formcolumncell">
-            <nobr>$Encoder.bodyEscape($fieldmapping.get('TARGETDISPLAY'))</nobr>
-          </td>
-        </tr>
-  #set($fieldcounter = $fieldcounter + 1)
-#end
-#if($fieldcounter == 0)
-        <tr class="formrow"><td class="formmessage" colspan="2">$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.NoFieldMappingSpecified'))</td></tr>
-#end
-      </table>
-    </td>
-  </tr>
-  <tr><td class="separator" colspan="2"><hr/></td></tr>
-  <tr>
-    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.KeepAllMetadata'))</nobr></td>
-    <td class="value"><nobr>$Encoder.bodyEscape($KEEPALLMETADATA)</nobr></td>
-  </tr>
-  <tr>
-    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.FilterEmpty'))</nobr></td>
-    <td class="value"><nobr>$Encoder.bodyEscape($FILTEREMPTY)</nobr></td>
-  </tr>
-
-  <tr>
-    <td class="separator" colspan="4"><hr/></td>
-  </tr>
-  <tr>
-    <td class="description" colspan="1"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.ForcedMetadataColon'))</nobr></td>
+    <td class="description" colspan="1"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.MetadataExpressionsColon'))</nobr></td>
     <td class="boxcell" colspan="3">
       <table class="formtable">
         <tr class="formheaderrow">
           <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.ParameterName'))</nobr></td>
-          <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.ParameterValue'))</nobr></td>
+          <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.RemoveQ'))</nobr></td>
+          <td class="formcolumnheader"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.ParameterValueExpression'))</nobr></td>
         </tr>
   #set($paramcounter = 0)
-  #foreach($paramrecord in $PARAMETERS)
+  #foreach($paramrecord in $EXPRESSIONS)
     #if(($paramcounter % 2) == 0)
         <tr class="evenformrow">
     #else
@@ -78,15 +36,34 @@
             <nobr>$Encoder.bodyEscape($paramrecord.get('parameter'))</nobr>
           </td>
           <td class="formcolumncell">
+            <nobr>
+    #if($paramrecord.get('isnull') == 'true')
+              $Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.True'))
+    #end
+    #if($paramrecord.get('isnull') == 'false')
+              $Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.False'))
+    #end
+            </nobr>
+          </td>
+          <td class="formcolumncell">
             <nobr>$Encoder.bodyEscape($paramrecord.get('value'))</nobr>
           </td>
         </tr>
     #set($paramcounter = $paramcounter + 1)
   #end
   #if($paramcounter == 0)
-        <tr class="formrow"><td colspan="2" class="formcolumnmessage"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.NoForcedMetadataSpecified'))</nobr></td></tr>
+        <tr class="formrow"><td colspan="4" class="formcolumnmessage"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.NoExpressionsSpecified'))</nobr></td></tr>
   #end
       </table>
     </td>
   </tr>
+  <tr><td class="separator" colspan="4"><hr/></td></tr>
+  <tr>
+    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.KeepAllMetadata'))</nobr></td>
+    <td class="value"><nobr>$Encoder.bodyEscape($KEEPALLMETADATA)</nobr></td>
+  </tr>
+  <tr>
+    <td class="description"><nobr>$Encoder.bodyEscape($ResourceBundle.getString('ForcedMetadata.FilterEmpty'))</nobr></td>
+    <td class="value"><nobr>$Encoder.bodyEscape($FILTEREMPTY)</nobr></td>
+  </tr>
 </table>

Modified: manifoldcf/branches/CONNECTORS-1134/framework/agents/src/main/java/org/apache/manifoldcf/agents/interfaces/RepositoryDocument.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-1134/framework/agents/src/main/java/org/apache/manifoldcf/agents/interfaces/RepositoryDocument.java?rev=1649449&r1=1649448&r2=1649449&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-1134/framework/agents/src/main/java/org/apache/manifoldcf/agents/interfaces/RepositoryDocument.java (original)
+++ manifoldcf/branches/CONNECTORS-1134/framework/agents/src/main/java/org/apache/manifoldcf/agents/interfaces/RepositoryDocument.java Mon Jan  5 00:39:43 2015
@@ -308,6 +308,17 @@ public class RepositoryDocument
     return binaryLength;
   }
 
+  /** Remove a field.
+  *@param fieldName is the field name.
+  */
+  public void removeField(String fieldName)
+  {
+    fields.remove(fieldName);
+    stringFields.remove(fieldName);
+    readerFields.remove(fieldName);
+    dateFields.remove(fieldName);
+  }
+  
   /** Add/remove a multivalue date field.
   *@param fieldName is the field name.
   *@param fieldData is the multi-valued data (an array of Dates).  Null means
@@ -476,6 +487,12 @@ public class RepositoryDocument
         newValues[i] = newValue.toString();
       }
       stringFields.put(fieldName,newValues);
+      // Reader is no longer useful, since we've read it to the end.
+      // Remove it from the record accordingly.
+      // NOTE WELL: This could cause side effects if the same
+      // field is accessed simultaneously two different ways!
+      readerFields.remove(fieldName);
+      fields.put(fieldName,newValues);
       return newValues;
     }
     else