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 2013/06/30 16:04:53 UTC

svn commit: r1498125 - in /manifoldcf/branches/CONNECTORS-703: connectors/regexpmapper/ connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/ connectors/regexpmapper/connector/src/main/native2ascii/org/apache...

Author: kwright
Date: Sun Jun 30 14:04:52 2013
New Revision: 1498125

URL: http://svn.apache.org/r1498125
Log:
Finish CONNECTORS-703.

Added:
    manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/MatchMap.java   (with props)
    manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpParameters.java   (with props)
Modified:
    manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/   (props changed)
    manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpMapper.java
    manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/native2ascii/org/apache/manifoldcf/authorities/mappers/regexp/common_en_US.properties
    manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/native2ascii/org/apache/manifoldcf/authorities/mappers/regexp/common_ja_JP.properties
    manifoldcf/branches/CONNECTORS-703/framework/authority-servlet/src/main/java/org/apache/manifoldcf/authorityservlet/UserACLServlet.java
    manifoldcf/branches/CONNECTORS-703/framework/crawler-ui/src/main/webapp/editauthority.jsp
    manifoldcf/branches/CONNECTORS-703/framework/crawler-ui/src/main/webapp/editmapper.jsp
    manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/mapping/MappingConnectionManager.java
    manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/system/Logging.java
    manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/system/ManifoldCF.java
    manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/ManifoldCF.java
    manifoldcf/branches/CONNECTORS-703/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_en_US.properties
    manifoldcf/branches/CONNECTORS-703/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_ja_JP.properties

Propchange: manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sun Jun 30 14:04:52 2013
@@ -0,0 +1,10 @@
+build
+dist
+doc
+target
+test-output
+test-derby-output
+test-postgresql-output
+test-HSQLDB-output
+test-HSQLDBext-output
+test-mysql-output

Added: manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/MatchMap.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/MatchMap.java?rev=1498125&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/MatchMap.java (added)
+++ manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/MatchMap.java Sun Jun 30 14:04:52 2013
@@ -0,0 +1,587 @@
+/* $Id$ */
+
+/**
+* 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.
+*/
+package org.apache.manifoldcf.authorities.mappers.regexp;
+
+import org.apache.manifoldcf.core.interfaces.*;
+import java.util.*;
+import java.util.regex.*;
+
+/** An instance of this class describes a "match map", which describes a translation of an input
+* string using regexp technology.
+* A match map consists of multiple clauses, which are fired in sequence.  Each clause is a regexp
+* search and replace, where the replace string can include references to the groups present in the
+* search regexp.
+* MatchMaps can be converted to strings in two different ways.  The first way is to build a single
+* string of the form "match1=replace1&match2=replace2...".  Strings of this kind must escape & and =
+* characters in the match and replace strings, where found.  The second way is to generate an array
+* of match strings and a corresponding array of replace strings.  This method requires no escaping
+* of the string contents.
+*/
+public class MatchMap
+{
+  public static final String _rcsid = "@(#)$Id$";
+
+  /** This is the set of match regexp strings */
+  protected List<String> matchStrings;
+  /** This is the set of Pattern objects corresponding to the match regexp strings.
+  * It's null if the patterns have not been built yet. */
+  protected Pattern[] matchPatterns = null;
+  /** This is the set of replace strings */
+  protected List<String> replaceStrings;
+
+  /** Constructor.  Build an empty matchmap. */
+  public MatchMap()
+  {
+    matchStrings = new ArrayList<String>();
+    replaceStrings = new ArrayList<String>();
+  }
+
+  /** Constructor.  Build a matchmap from a single string. */
+  public MatchMap(String stringForm)
+  {
+    matchStrings = new ArrayList<String>();
+    replaceStrings = new ArrayList<String>();
+    StringBuilder matchString = new StringBuilder();
+    StringBuilder replaceString = new StringBuilder();
+    int i = 0;
+    while (i < stringForm.length())
+    {
+      matchString.setLength(0);
+      replaceString.setLength(0);
+      while (i < stringForm.length())
+      {
+        char x = stringForm.charAt(i);
+        if (x == '&' || x == '=')
+          break;
+        i++;
+        if (x == '\\' && i < stringForm.length())
+          x = stringForm.charAt(i++);
+        matchString.append(x);
+      }
+
+      if (i < stringForm.length())
+      {
+        char x = stringForm.charAt(i);
+        if (x == '=')
+        {
+          i++;
+          // Pick up the second string
+          while (i < stringForm.length())
+          {
+            x = stringForm.charAt(i);
+            if (x == '&')
+              break;
+            i++;
+            if (x == '\\' && i < stringForm.length())
+              x = stringForm.charAt(i++);
+            replaceString.append(x);
+          }
+        }
+      }
+
+      matchStrings.add(matchString.toString());
+      replaceStrings.add(replaceString.toString());
+
+      if (i < stringForm.length())
+      {
+        char x = stringForm.charAt(i);
+        if (x == '&')
+          i++;
+      }
+    }
+  }
+
+  /** Constructor.  Build a matchmap from two lists representing match and replace strings */
+  public MatchMap(List<String> matchStrings, List<String> replaceStrings)
+  {
+    this.matchStrings = matchStrings;
+    this.replaceStrings = replaceStrings;
+  }
+
+  /** Get the number of match/replace strings */
+  public int getMatchCount()
+  {
+    return matchStrings.size();
+  }
+
+  /** Get a specific match string */
+  public String getMatchString(int index)
+  {
+    return matchStrings.get(index);
+  }
+
+  /** Get a specific replace string */
+  public String getReplaceString(int index)
+  {
+    return replaceStrings.get(index);
+  }
+
+  /** Delete a specified match/replace string pair */
+  public void deleteMatchPair(int index)
+  {
+    matchStrings.remove(index);
+    replaceStrings.remove(index);
+    matchPatterns = null;
+  }
+
+  /** Insert a match/replace string pair */
+  public void insertMatchPair(int index, String match, String replace)
+  {
+    matchStrings.add(index,match);
+    replaceStrings.add(index,replace);
+    matchPatterns = null;
+  }
+
+  /** Append a match/replace string pair */
+  public void appendMatchPair(String match, String replace)
+  {
+    matchStrings.add(match);
+    replaceStrings.add(replace);
+    matchPatterns = null;
+  }
+
+  /** Append old-style match/replace pair.
+  * This method translates old-style regexp and group output form to the
+  * current style before adding to the map.
+  */
+  public void appendOldstyleMatchPair(String oldstyleMatch, String oldstyleReplace)
+  {
+    String newStyleMatch = "^" + oldstyleMatch + "$";
+
+    // Need to build a new-style replace string from the old one.  To do that, use the
+    // original parser (which basically will guarantee that we get it right)
+
+    EvaluatorTokenStream et = new EvaluatorTokenStream(oldstyleReplace);
+    StringBuilder newStyleReplace = new StringBuilder();
+
+    while (true)
+    {
+      EvaluatorToken t = et.peek();
+      if (t == null)
+        break;
+      switch (t.getType())
+      {
+      case EvaluatorToken.TYPE_COMMA:
+        et.advance();
+        break;
+      case EvaluatorToken.TYPE_GROUP:
+        et.advance();
+        int groupNumber = t.getGroupNumber();
+        switch (t.getGroupStyle())
+        {
+        case EvaluatorToken.GROUPSTYLE_NONE:
+          newStyleReplace.append("$(").append(Integer.toString(groupNumber)).append(")");
+          break;
+        case EvaluatorToken.GROUPSTYLE_LOWER:
+          newStyleReplace.append("$(").append(Integer.toString(groupNumber)).append("l)");
+          break;
+        case EvaluatorToken.GROUPSTYLE_UPPER:
+          newStyleReplace.append("$(").append(Integer.toString(groupNumber)).append("u)");
+          break;
+        case EvaluatorToken.GROUPSTYLE_MIXED:
+          newStyleReplace.append("$(").append(Integer.toString(groupNumber)).append("m)");
+          break;
+        default:
+          break;
+        }
+        break;
+      case EvaluatorToken.TYPE_TEXT:
+        et.advance();
+        escape(newStyleReplace,t.getTextValue());
+        break;
+      default:
+        break;
+      }
+    }
+
+    appendMatchPair(newStyleMatch,newStyleReplace.toString());
+  }
+
+  /** Escape a string so it is verbatim */
+  protected static void escape(StringBuilder output, String input)
+  {
+    int i = 0;
+    while (i < input.length())
+    {
+      char x = input.charAt(i++);
+      if (x == '$')
+        output.append(x);
+      output.append(x);
+    }
+  }
+
+  /** Convert the matchmap to string form. */
+  public String toString()
+  {
+    int i = 0;
+    StringBuilder rval = new StringBuilder();
+    while (i < matchStrings.size())
+    {
+      String matchString = matchStrings.get(i);
+      String replaceString = replaceStrings.get(i);
+      if (i > 0)
+        rval.append('&');
+      stuff(rval,matchString);
+      rval.append('=');
+      stuff(rval,replaceString);
+      i++;
+    }
+    return rval.toString();
+  }
+
+  /** Stuff characters */
+  protected static void stuff(StringBuilder sb, String value)
+  {
+    int i = 0;
+    while (i < value.length())
+    {
+      char x = value.charAt(i++);
+      if (x == '\\' || x == '&' || x == '=')
+        sb.append('\\');
+      sb.append(x);
+    }
+  }
+
+  /** Perform a translation.
+  */
+  public String translate(String input)
+    throws ManifoldCFException
+  {
+    // Build pattern vector if not already there
+    if (matchPatterns == null)
+    {
+      matchPatterns = new Pattern[matchStrings.size()];
+      int i = 0;
+      while (i < matchPatterns.length)
+      {
+        String regexp = matchStrings.get(i);
+        try
+        {
+          matchPatterns[i] = Pattern.compile(regexp);
+        }
+        catch (java.util.regex.PatternSyntaxException e)
+        {
+          matchPatterns = null;
+          throw new ManifoldCFException("For match expression '"+regexp+"', found pattern syntax error: "+e.getMessage(),e);
+        }
+        i++;
+      }
+    }
+
+    int j = 0;
+    while (j < matchPatterns.length)
+    {
+      Pattern p = matchPatterns[j];
+      // Construct a matcher
+      Matcher m = p.matcher(input);
+      // Grab the output description
+      String outputDescription = replaceStrings.get(j);
+      j++;
+      // Create a copy buffer
+      StringBuilder outputBuffer = new StringBuilder();
+      // Keep track of the index in the original string we have done up to
+      int currentIndex = 0;
+      // Scan the string using find, and for each one found, do a translation
+      while (true)
+      {
+        boolean foundOne = m.find();
+        if (foundOne == false)
+        {
+          // No subsequent match found.
+          // Copy everything from currentIndex until the end of input
+          outputBuffer.append(input.substring(currentIndex));
+          break;
+        }
+
+        // Do a translation.  This involves copying everything in the input
+        // string up until the start of the match, then doing a replace for
+        // the match itself, and finally setting the currentIndex to the end
+        // of the match.
+
+        int matchStart = m.start(0);
+        int matchEnd = m.end(0);
+        if (matchStart == -1)
+        {
+          // The expression was degenerate; treat this as the end.
+          outputBuffer.append(input.substring(currentIndex));
+          break;
+        }
+        outputBuffer.append(input.substring(currentIndex,matchStart));
+
+        // Process translation description!
+        int i = 0;
+        while (i < outputDescription.length())
+        {
+          char x = outputDescription.charAt(i++);
+          if (x == '$' && i < outputDescription.length())
+          {
+            x = outputDescription.charAt(i++);
+            if (x == '(')
+            {
+              // Process evaluation expression
+              StringBuilder numberBuf = new StringBuilder();
+              boolean upper = false;
+              boolean lower = false;
+              boolean mixed = false;
+              while (i < outputDescription.length())
+              {
+                char y = outputDescription.charAt(i++);
+                if (y == ')')
+                  break;
+                else if (y >= '0' && y <= '9')
+                  numberBuf.append(y);
+                else if (y == 'u' || y == 'U')
+                  upper = true;
+                else if (y == 'l' || y == 'L')
+                  lower = true;
+                else if (y == 'm' || y == 'M')
+                  mixed = true;
+              }
+              String number = numberBuf.toString();
+              try
+              {
+                int groupnum = Integer.parseInt(number);
+                String groupValue = m.group(groupnum);
+                if (upper)
+                  outputBuffer.append(groupValue.toUpperCase());
+                else if (lower)
+                  outputBuffer.append(groupValue.toLowerCase());
+                else if (mixed && groupValue.length() > 0)
+                  outputBuffer.append(groupValue.substring(0,1).toUpperCase()).append(groupValue.substring(1).toLowerCase());
+                else
+                  outputBuffer.append(groupValue);
+
+              }
+              catch (NumberFormatException e)
+              {
+                // Silently skip, because it's an illegal group number, so nothing
+                // gets added.
+              }
+
+              // Go back around, so we don't add the $ in
+              continue;
+            }
+          }
+          outputBuffer.append(x);
+        }
+
+        currentIndex = matchEnd;
+      }
+
+      input = outputBuffer.toString();
+    }
+
+    return input;
+  }
+
+
+  // Protected classes
+
+  // These classes are used to process the old token-based replacement strings
+
+  /** Evaluator token.
+  */
+  protected static class EvaluatorToken
+  {
+    public final static int TYPE_GROUP = 0;
+    public final static int TYPE_TEXT = 1;
+    public final static int TYPE_COMMA = 2;
+
+    public final static int GROUPSTYLE_NONE = 0;
+    public final static int GROUPSTYLE_LOWER = 1;
+    public final static int GROUPSTYLE_UPPER = 2;
+    public final static int GROUPSTYLE_MIXED = 3;
+
+    protected int type;
+    protected int groupNumber = -1;
+    protected int groupStyle = GROUPSTYLE_NONE;
+    protected String textValue = null;
+
+    public EvaluatorToken()
+    {
+      type = TYPE_COMMA;
+    }
+
+    public EvaluatorToken(int groupNumber, int groupStyle)
+    {
+      type = TYPE_GROUP;
+      this.groupNumber = groupNumber;
+      this.groupStyle = groupStyle;
+    }
+
+    public EvaluatorToken(String text)
+    {
+      type = TYPE_TEXT;
+      this.textValue = text;
+    }
+
+    public int getType()
+    {
+      return type;
+    }
+
+    public int getGroupNumber()
+    {
+      return groupNumber;
+    }
+
+    public int getGroupStyle()
+    {
+      return groupStyle;
+    }
+
+    public String getTextValue()
+    {
+      return textValue;
+    }
+
+  }
+
+
+  /** Token stream.
+  */
+  protected static class EvaluatorTokenStream
+  {
+    protected String text;
+    protected int pos;
+    protected EvaluatorToken token = null;
+
+    /** Constructor.
+    */
+    public EvaluatorTokenStream(String text)
+    {
+      this.text = text;
+      this.pos = 0;
+    }
+
+    /** Get current token.
+    */
+    public EvaluatorToken peek()
+    {
+      if (token == null)
+      {
+        token = nextToken();
+      }
+      return token;
+    }
+
+    /** Go on to next token.
+    */
+    public void advance()
+    {
+      token = null;
+    }
+
+    protected EvaluatorToken nextToken()
+    {
+      char x;
+      // Fetch the next token
+      while (true)
+      {
+        if (pos == text.length())
+          return null;
+        x = text.charAt(pos);
+        if (x > ' ')
+          break;
+        pos++;
+      }
+
+      StringBuilder sb;
+
+      if (x == '"')
+      {
+        // Parse text
+        pos++;
+        sb = new StringBuilder();
+        while (true)
+        {
+          if (pos == text.length())
+            break;
+          x = text.charAt(pos);
+          pos++;
+          if (x == '"')
+          {
+            break;
+          }
+          if (x == '\\')
+          {
+            if (pos == text.length())
+              break;
+            x = text.charAt(pos++);
+          }
+          sb.append(x);
+        }
+
+        return new EvaluatorToken(sb.toString());
+      }
+
+      if (x == ',')
+      {
+        pos++;
+        return new EvaluatorToken();
+      }
+
+      // Eat number at beginning
+      sb = new StringBuilder();
+      while (true)
+      {
+        if (pos == text.length())
+          break;
+        x = text.charAt(pos);
+        if (x >= '0' && x <= '9')
+        {
+          sb.append(x);
+          pos++;
+          continue;
+        }
+        break;
+      }
+      String numberValue = sb.toString();
+      int groupNumber = 0;
+      if (numberValue.length() > 0)
+        groupNumber = new Integer(numberValue).intValue();
+      // Save the next char position
+      int modifierPos = pos;
+      // Go to the end of the word
+      while (true)
+      {
+        if (pos == text.length())
+          break;
+        x = text.charAt(pos);
+        if (x == ',' || x >= '0' && x <= '9' || x <= ' ' && x >= 0)
+          break;
+        pos++;
+      }
+
+      int style = EvaluatorToken.GROUPSTYLE_NONE;
+      if (modifierPos != pos)
+      {
+        String modifier = text.substring(modifierPos,pos);
+        if (modifier.startsWith("u"))
+          style = EvaluatorToken.GROUPSTYLE_UPPER;
+        else if (modifier.startsWith("l"))
+          style = EvaluatorToken.GROUPSTYLE_LOWER;
+        else if (modifier.startsWith("m"))
+          style = EvaluatorToken.GROUPSTYLE_MIXED;
+      }
+      return new EvaluatorToken(groupNumber,style);
+    }
+  }
+
+}

Propchange: manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/MatchMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/MatchMap.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpMapper.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpMapper.java?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpMapper.java (original)
+++ manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpMapper.java Sun Jun 30 14:04:52 2013
@@ -33,15 +33,36 @@ public class RegexpMapper extends org.ap
 {
   public static final String _rcsid = "@(#)$Id$";
 
+  // Match map for username
+  private MatchMap matchMap = null;
+
   /** Constructor.
   */
   public RegexpMapper()
   {
   }
 
+  /** Close the connection.  Call this before discarding the mapping connection.
+  */
+  @Override
+  public void disconnect()
+    throws ManifoldCFException
+  {
+    matchMap = null;
+    super.disconnect();
+  }
+
   // All methods below this line will ONLY be called if a connect() call succeeded
   // on this instance!
 
+  private MatchMap getSession()
+    throws ManifoldCFException
+  {
+    if (matchMap == null)
+      matchMap = new MatchMap(params.getParameter(RegexpParameters.userNameMapping));
+    return matchMap;
+  }
+
   /** Map an input user name to an output name.
   *@param userName is the name to map
   *@return the mapped user name
@@ -50,8 +71,14 @@ public class RegexpMapper extends org.ap
   public String mapUser(String userName)
     throws ManifoldCFException
   {
-    // MHL
-    return userName;
+    MatchMap mm = getSession();
+    
+    String outputUserName = mm.translate(userName);
+    
+    if (Logging.mappingConnectors.isDebugEnabled())
+      Logging.mappingConnectors.debug("RegexpMapper: Input user name '"+userName+"'; output user name '"+outputUserName+"'");
+    
+    return outputUserName;
   }
 
   // UI support methods.
@@ -72,19 +99,33 @@ public class RegexpMapper extends org.ap
     Locale locale, ConfigParams parameters, List<String> tabsArray)
     throws ManifoldCFException, IOException
   {
+    tabsArray.add(Messages.getString(locale,"RegexpMapper.UserMapping"));
+
     out.print(
 "<script type=\"text/javascript\">\n"+
 "<!--\n"+
 "function checkConfig()\n"+
 "{\n"+
+"  if (editconnection.usernameregexp.value != \"\" && !isRegularExpression(editconnection.usernameregexp.value))\n"+
+"  {\n"+
+"    alert(\"" + Messages.getBodyJavascriptString(locale,"RegexpMapper.UserNameRegularExpressionMustBeValidRegularExpression") + "\");\n"+
+"    editconnection.usernameregexp.focus();\n"+
+"    return false;\n"+
+"  }\n"+
 "  return true;\n"+
 "}\n"+
 "\n"+
 "function checkConfigForSave()\n"+
 "{\n"+
+"  if (editconnection.usernameregexp.value == \"\")\n"+
+"  {\n"+
+"    alert(\"" + Messages.getBodyJavascriptString(locale,"RegexpMapper.UserNameRegularExpressionCannotBeNull") + "\");\n"+
+"    SelectTab(\"" + Messages.getBodyJavascriptString(locale,"RegexpMapper.UserMapping") + "\");\n"+
+"    editconnection.usernameregexp.focus();\n"+
+"    return false;\n"+
+"  }\n"+
 "  return true;\n"+
 "}\n"+
-"\n"+
 "//-->\n"+
 "</script>\n"
     );
@@ -104,7 +145,40 @@ public class RegexpMapper extends org.ap
     Locale locale, ConfigParams parameters, String tabName)
     throws ManifoldCFException, IOException
   {
-    // Does nothing
+    String userNameMapping = parameters.getParameter(RegexpParameters.userNameMapping);
+    if (userNameMapping == null)
+      userNameMapping = "^(.*)\\\\@([A-Z|a-z|0-9|_|-]*)\\\\.(.*)$=$(2)\\\\$(1l)";
+    MatchMap matchMap = new MatchMap(userNameMapping);
+
+    String usernameRegexp = matchMap.getMatchString(0);
+    String livelinkUserExpr = matchMap.getReplaceString(0);
+
+    // The "User Mapping" tab
+    if (tabName.equals(Messages.getString(locale,"RegexpMapper.UserMapping")))
+    {
+      out.print(
+"<table class=\"displaytable\">\n"+
+"  <tr><td class=\"separator\" colspan=\"2\"><hr/></td></tr>\n"+
+"  <tr>\n"+
+"    <td class=\"description\"><nobr>" + Messages.getBodyString(locale,"RegexpMapper.UserNameRegularExpressionColon") + "</nobr></td>\n"+
+"    <td class=\"value\"><input type=\"text\" size=\"40\" name=\"usernameregexp\" value=\""+org.apache.manifoldcf.ui.util.Encoder.attributeEscape(usernameRegexp)+"\"/></td>\n"+
+"  </tr>\n"+
+"  <tr>\n"+
+"    <td class=\"description\"><nobr>" + Messages.getBodyString(locale,"RegexpMapper.UserExpressionColon") + "</nobr></td>\n"+
+"    <td class=\"value\"><input type=\"text\" size=\"40\" name=\"livelinkuserexpr\" value=\""+org.apache.manifoldcf.ui.util.Encoder.attributeEscape(livelinkUserExpr)+"\"/></td>\n"+
+"  </tr>\n"+
+"</table>\n"
+      );
+    }
+    else
+    {
+      // Hiddens for "User Mapping" tab
+      out.print(
+"<input type=\"hidden\" name=\"usernameregexp\" value=\""+org.apache.manifoldcf.ui.util.Encoder.attributeEscape(usernameRegexp)+"\"/>\n"+
+"<input type=\"hidden\" name=\"livelinkuserexpr\" value=\""+org.apache.manifoldcf.ui.util.Encoder.attributeEscape(livelinkUserExpr)+"\"/>\n"
+      );
+    }
+
   }
   
   /** Process a configuration post.
@@ -121,6 +195,16 @@ public class RegexpMapper extends org.ap
     Locale locale, ConfigParams parameters)
     throws ManifoldCFException
   {
+    // User name parameters
+    String usernameRegexp = variableContext.getParameter("usernameregexp");
+    String livelinkUserExpr = variableContext.getParameter("livelinkuserexpr");
+    if (usernameRegexp != null && livelinkUserExpr != null)
+    {
+      MatchMap matchMap = new MatchMap();
+      matchMap.appendMatchPair(usernameRegexp,livelinkUserExpr);
+      parameters.setParameter(RegexpParameters.userNameMapping,matchMap.toString());
+    }
+
     return null;
   }
   
@@ -136,7 +220,25 @@ public class RegexpMapper extends org.ap
     Locale locale, ConfigParams parameters)
     throws ManifoldCFException, IOException
   {
-    // Does nothing
+    MatchMap matchMap = new MatchMap(parameters.getParameter(RegexpParameters.userNameMapping));
+
+    String usernameRegexp = matchMap.getMatchString(0);
+    String livelinkUserExpr = matchMap.getReplaceString(0);
+
+    out.print(
+"<table class=\"displaytable\">\n"+
+"  <tr><td class=\"separator\" colspan=\"2\"><hr/></td></tr>\n"+
+"  <tr>\n"+
+"    <td class=\"description\"><nobr>" + Messages.getBodyString(locale,"RegexpMapper.UserNameRegularExpressionColon") + "</nobr></td>\n"+
+"    <td class=\"value\"><nobr>"+org.apache.manifoldcf.ui.util.Encoder.bodyEscape(usernameRegexp)+"</nobr></td>\n"+
+"  </tr>\n"+
+"  <tr>\n"+
+"    <td class=\"description\"><nobr>" + Messages.getBodyString(locale,"RegexpMapper.UserExpressionColon") + "</nobr></td>\n"+
+"    <td class=\"value\"><nobr>"+org.apache.manifoldcf.ui.util.Encoder.bodyEscape(livelinkUserExpr)+"</nobr></td>\n"+
+"  </tr>\n"+
+"</table>\n"
+    );
+
   }
 
 }

Added: manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpParameters.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpParameters.java?rev=1498125&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpParameters.java (added)
+++ manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpParameters.java Sun Jun 30 14:04:52 2013
@@ -0,0 +1,30 @@
+/* $Id$ */
+
+/**
+* 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.
+*/
+package org.apache.manifoldcf.authorities.mappers.regexp;
+
+/** This class describes regexp mapper parameters.
+*/
+public class RegexpParameters
+{
+  public static final String _rcsid = "@(#)$Id$";
+
+  /** User name mapping description. */
+  public final static String userNameMapping = "User name map";
+
+}

Propchange: manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpParameters.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/java/org/apache/manifoldcf/authorities/mappers/regexp/RegexpParameters.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/native2ascii/org/apache/manifoldcf/authorities/mappers/regexp/common_en_US.properties
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/native2ascii/org/apache/manifoldcf/authorities/mappers/regexp/common_en_US.properties?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/native2ascii/org/apache/manifoldcf/authorities/mappers/regexp/common_en_US.properties (original)
+++ manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/native2ascii/org/apache/manifoldcf/authorities/mappers/regexp/common_en_US.properties Sun Jun 30 14:04:52 2013
@@ -13,4 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-#RegexpMapper.xxx
+RegexpMapper.UserMapping=User Mapping
+RegexpMapper.UserNameRegularExpressionColon=User name regular expression:
+RegexpMapper.UserExpressionColon=User expression:
+RegexpMapper.UserNameRegularExpressionMustBeValidRegularExpression=User name regular expression must be a valid regular expression
+RegexpMapper.UserNameRegularExpressionCannotBeNull=User name regular expression cannot be null

Modified: manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/native2ascii/org/apache/manifoldcf/authorities/mappers/regexp/common_ja_JP.properties
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/native2ascii/org/apache/manifoldcf/authorities/mappers/regexp/common_ja_JP.properties?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/native2ascii/org/apache/manifoldcf/authorities/mappers/regexp/common_ja_JP.properties (original)
+++ manifoldcf/branches/CONNECTORS-703/connectors/regexpmapper/connector/src/main/native2ascii/org/apache/manifoldcf/authorities/mappers/regexp/common_ja_JP.properties Sun Jun 30 14:04:52 2013
@@ -13,3 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+RegexpMapper.UserMapping=User Mapping
+RegexpMapper.UserNameRegularExpressionColon=User name regular expression:
+RegexpMapper.UserExpressionColon=User expression:
+RegexpMapper.UserNameRegularExpressionMustBeValidRegularExpression=User name regular expression must be a valid regular expression
+RegexpMapper.UserNameRegularExpressionCannotBeNull=User name regular expression cannot be null

Modified: manifoldcf/branches/CONNECTORS-703/framework/authority-servlet/src/main/java/org/apache/manifoldcf/authorityservlet/UserACLServlet.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/framework/authority-servlet/src/main/java/org/apache/manifoldcf/authorityservlet/UserACLServlet.java?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/framework/authority-servlet/src/main/java/org/apache/manifoldcf/authorityservlet/UserACLServlet.java (original)
+++ manifoldcf/branches/CONNECTORS-703/framework/authority-servlet/src/main/java/org/apache/manifoldcf/authorityservlet/UserACLServlet.java Sun Jun 30 14:04:52 2013
@@ -200,6 +200,7 @@ public class UserACLServlet extends Http
         // Otherwise, we just fire off the request
         if (thisConnection.getPrerequisiteMapping() == null)
         {
+          ar.setUserID(userID);
           queue.addRequest(ar);
         }
         else
@@ -230,10 +231,12 @@ public class UserACLServlet extends Http
         // Either start up a thread, or just fire it off immediately.
         if (thisConnection.getPrerequisiteMapping() == null)
         {
+          mr.setUserID(userID);
           mappingQueue.addRequest(mr);
         }
         else
         {
+          //System.out.println("Mapper: prerequisite found: '"+thisConnection.getPrerequisiteMapping()+"'");
           MappingOrderThread thread = new MappingOrderThread(identifyingString,
             mr, thisConnection.getPrerequisiteMapping(), mappingQueue, mappingRequests);
           mappingThreads.add(thread);

Modified: manifoldcf/branches/CONNECTORS-703/framework/crawler-ui/src/main/webapp/editauthority.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/framework/crawler-ui/src/main/webapp/editauthority.jsp?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/framework/crawler-ui/src/main/webapp/editauthority.jsp (original)
+++ manifoldcf/branches/CONNECTORS-703/framework/crawler-ui/src/main/webapp/editauthority.jsp Sun Jun 30 14:04:52 2013
@@ -85,9 +85,11 @@
 	// Set up the predefined tabs
 	tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editauthority.Name"));
 	tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editauthority.Type"));
-	tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editauthority.Prerequisites"));
 	if (className.length() > 0)
+	{
+		tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editauthority.Prerequisites"));
 		tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editauthority.Throttling"));
+	}
 
 %>
 

Modified: manifoldcf/branches/CONNECTORS-703/framework/crawler-ui/src/main/webapp/editmapper.jsp
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/framework/crawler-ui/src/main/webapp/editmapper.jsp?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/framework/crawler-ui/src/main/webapp/editmapper.jsp (original)
+++ manifoldcf/branches/CONNECTORS-703/framework/crawler-ui/src/main/webapp/editmapper.jsp Sun Jun 30 14:04:52 2013
@@ -83,9 +83,11 @@
 	// Set up the predefined tabs
 	tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editmapper.Name"));
 	tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editmapper.Type"));
-	tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editmapper.Prerequisites"));
 	if (className.length() > 0)
+	{
+		tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editmapper.Prerequisites"));
 		tabsArray.add(Messages.getString(pageContext.getRequest().getLocale(),"editmapper.Throttling"));
+	}
 
 %>
 

Modified: manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/mapping/MappingConnectionManager.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/mapping/MappingConnectionManager.java?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/mapping/MappingConnectionManager.java (original)
+++ manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/mapping/MappingConnectionManager.java Sun Jun 30 14:04:52 2013
@@ -47,7 +47,7 @@ public class MappingConnectionManager ex
   // Special field suffix
   private final static String passwordSuffix = "password";
 
-  protected final static String nameField = "mappingname";      // Changed this to work around a bug in postgresql
+  protected final static String nameField = "connname";      // Changed this to work around a bug in postgresql
   protected final static String descriptionField = "description";
   protected final static String classNameField = "classname";
   protected final static String maxCountField = "maxcount";

Modified: manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/system/Logging.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/system/Logging.java?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/system/Logging.java (original)
+++ manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/system/Logging.java Sun Jun 30 14:04:52 2013
@@ -32,6 +32,7 @@ public class Logging extends org.apache.
   // Public logger objects
   public static Logger authorityService = null;
   public static Logger authorityConnectors = null;
+  public static Logger mappingConnectors = null;
 
   /** Initialize logger setup.
   */
@@ -45,6 +46,7 @@ public class Logging extends org.apache.
     // package loggers
     authorityService = newLogger("org.apache.manifoldcf.authorityservice");
     authorityConnectors = newLogger("org.apache.manifoldcf.authorityconnectors");
+    mappingConnectors = newLogger("org.apache.manifoldcf.mappingconnectors");
   }
 
 

Modified: manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/system/ManifoldCF.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/system/ManifoldCF.java?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/system/ManifoldCF.java (original)
+++ manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/authorities/system/ManifoldCF.java Sun Jun 30 14:04:52 2013
@@ -196,6 +196,7 @@ public class ManifoldCF extends org.apac
     idleCleanupThread.start();
 
     requestQueue = new RequestQueue<AuthRequest>();
+    mappingRequestQueue = new RequestQueue<MappingRequest>();
 
     authCheckThreads = new AuthCheckThread[numAuthCheckThreads];
     for (int i = 0; i < numAuthCheckThreads; i++)

Modified: manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/ManifoldCF.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/ManifoldCF.java?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/ManifoldCF.java (original)
+++ manifoldcf/branches/CONNECTORS-703/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/system/ManifoldCF.java Sun Jun 30 14:04:52 2013
@@ -1688,9 +1688,11 @@ public class ManifoldCF extends org.apac
   protected static final String API_REPOSITORYCONNECTORNODE = "repositoryconnector";
   protected static final String API_OUTPUTCONNECTORNODE = "outputconnector";
   protected static final String API_AUTHORITYCONNECTORNODE = "authorityconnector";
+  protected static final String API_MAPPINGCONNECTORNODE = "mappingconnector";
   protected static final String API_REPOSITORYCONNECTIONNODE = "repositoryconnection";
   protected static final String API_OUTPUTCONNECTIONNODE = "outputconnection";
   protected static final String API_AUTHORITYCONNECTIONNODE = "authorityconnection";
+  protected static final String API_MAPPINGCONNECTIONNODE = "mappingconnection";
   protected static final String API_CHECKRESULTNODE = "check_result";
   protected static final String API_JOBIDNODE = "job_id";
   protected static final String API_CONNECTIONNAMENODE = "connection_name";
@@ -1873,6 +1875,47 @@ public class ManifoldCF extends org.apac
     }
     return READRESULT_FOUND;
   }
+
+  /** Read a mapping connection status */
+  protected static int apiReadMappingConnectionStatus(IThreadContext tc, Configuration output, String connectionName)
+    throws ManifoldCFException
+  {
+    try
+    {
+      IMappingConnectionManager connectionManager = MappingConnectionManagerFactory.make(tc);
+      IMappingConnection connection = connectionManager.load(connectionName);
+      if (connection == null)
+      {
+        createErrorNode(output,"Connection '"+connectionName+"' does not exist");
+        return READRESULT_NOTFOUND;
+      }
+          
+      String results;
+      // Grab a connection handle, and call the test method
+      IMappingConnector connector = MappingConnectorFactory.grab(tc,connection.getClassName(),connection.getConfigParams(),connection.getMaxConnections());
+      try
+      {
+        results = connector.check();
+      }
+      catch (ManifoldCFException e)
+      {
+        results = e.getMessage();
+      }
+      finally
+      {
+        MappingConnectorFactory.release(connector);
+      }
+          
+      ConfigurationNode response = new ConfigurationNode(API_CHECKRESULTNODE);
+      response.setValue(results);
+      output.addChild(output.getChildCount(),response);
+    }
+    catch (ManifoldCFException e)
+    {
+      createErrorNode(output,e);
+    }
+    return READRESULT_FOUND;
+  }
   
   /** Read a repository connection status */
   protected static int apiReadRepositoryConnectionStatus(IThreadContext tc, Configuration output, String connectionName)
@@ -2120,6 +2163,29 @@ public class ManifoldCF extends org.apac
     return READRESULT_FOUND;
   }
 
+  /** Get mapping connections */
+  protected static int apiReadMappingConnections(IThreadContext tc, Configuration output)
+    throws ManifoldCFException
+  {
+    try
+    {
+      IMappingConnectionManager connManager = MappingConnectionManagerFactory.make(tc);
+      IMappingConnection[] connections = connManager.getAllConnections();
+      int i = 0;
+      while (i < connections.length)
+      {
+        ConfigurationNode connectionNode = new ConfigurationNode(API_MAPPINGCONNECTIONNODE);
+        formatMappingConnection(connectionNode,connections[i++]);
+        output.addChild(output.getChildCount(),connectionNode);
+      }
+    }
+    catch (ManifoldCFException e)
+    {
+      createErrorNode(output,e);
+    }
+    return READRESULT_FOUND;
+  }
+
   /** Read authority connection */
   protected static int apiReadAuthorityConnection(IThreadContext tc, Configuration output, String connectionName)
     throws ManifoldCFException
@@ -2148,6 +2214,34 @@ public class ManifoldCF extends org.apac
     return READRESULT_FOUND;
   }
 
+  /** Read mapping connection */
+  protected static int apiReadMappingConnection(IThreadContext tc, Configuration output, String connectionName)
+    throws ManifoldCFException
+  {
+    try
+    {
+      IMappingConnectionManager connectionManager = MappingConnectionManagerFactory.make(tc);
+      IMappingConnection connection = connectionManager.load(connectionName);
+      if (connection != null)
+      {
+        // Fill the return object with job information
+        ConfigurationNode connectionNode = new ConfigurationNode(API_MAPPINGCONNECTIONNODE);
+        formatMappingConnection(connectionNode,connection);
+        output.addChild(output.getChildCount(),connectionNode);
+      }
+      else
+      {
+        createErrorNode(output,"Mapping connection '"+connectionName+"' does not exist.");
+        return READRESULT_NOTFOUND;
+      }
+    }
+    catch (ManifoldCFException e)
+    {
+      createErrorNode(output,e);
+    }
+    return READRESULT_FOUND;
+  }
+
   /** Get repository connections */
   protected static int apiReadRepositoryConnections(IThreadContext tc, Configuration output)
     throws ManifoldCFException
@@ -2273,6 +2367,43 @@ public class ManifoldCF extends org.apac
     return READRESULT_FOUND;
   }
 
+  /** List mapping connectors */
+  protected static int apiReadMappingConnectors(IThreadContext tc, Configuration output)
+    throws ManifoldCFException
+  {
+    // List registered authority connectors
+    try
+    {
+      IMappingConnectorManager manager = MappingConnectorManagerFactory.make(tc);
+      IResultSet resultSet = manager.getConnectors();
+      int j = 0;
+      while (j < resultSet.getRowCount())
+      {
+        IResultRow row = resultSet.getRow(j++);
+        ConfigurationNode child = new ConfigurationNode(API_MAPPINGCONNECTORNODE);
+        String description = (String)row.getValue("description");
+        String className = (String)row.getValue("classname");
+        ConfigurationNode node;
+        if (description != null)
+        {
+          node = new ConfigurationNode(CONNECTORNODE_DESCRIPTION);
+          node.setValue(description);
+          child.addChild(child.getChildCount(),node);
+        }
+        node = new ConfigurationNode(CONNECTORNODE_CLASSNAME);
+        node.setValue(className);
+        child.addChild(child.getChildCount(),node);
+
+        output.addChild(output.getChildCount(),child);
+      }
+    }
+    catch (ManifoldCFException e)
+    {
+      createErrorNode(output,e);
+    }
+    return READRESULT_FOUND;
+  }
+
   /** List repository connectors */
   protected static int apiReadRepositoryConnectors(IThreadContext tc, Configuration output)
     throws ManifoldCFException
@@ -2983,6 +3114,10 @@ public class ManifoldCF extends org.apac
       {
         return apiReadOutputConnectionStatus(tc,output,connectionName);
       }
+      else if (connectionType.equals("mappingconnections"))
+      {
+        return apiReadMappingConnectionStatus(tc,output,connectionName);
+      }
       else if (connectionType.equals("authorityconnections"))
       {
         return apiReadAuthorityConnectionStatus(tc,output,connectionName);
@@ -3055,6 +3190,15 @@ public class ManifoldCF extends org.apac
       String connectionName = decodeAPIPathElement(path.substring("outputconnections/".length()));
       return apiReadOutputConnection(tc,output,connectionName);
     }
+    else if (path.equals("mappingconnections"))
+    {
+      return apiReadMappingConnections(tc,output);
+    }
+    else if (path.startsWith("mappingconnections/"))
+    {
+      String connectionName = decodeAPIPathElement(path.substring("mappingconnections/".length()));
+      return apiReadMappingConnection(tc,output,connectionName);
+    }
     else if (path.equals("authorityconnections"))
     {
       return apiReadAuthorityConnections(tc,output);
@@ -3077,6 +3221,10 @@ public class ManifoldCF extends org.apac
     {
       return apiReadOutputConnectors(tc,output);
     }
+    else if (path.equals("mappingconnectors"))
+    {
+      return apiReadMappingConnectors(tc,output);
+    }
     else if (path.equals("authorityconnectors"))
     {
       return apiReadAuthorityConnectors(tc,output);
@@ -3360,6 +3508,41 @@ public class ManifoldCF extends org.apac
     return WRITERESULT_FOUND;
   }
   
+  /** Write mapping connection.
+  */
+  protected static int apiWriteMappingConnection(IThreadContext tc, Configuration output, Configuration input, String connectionName)
+    throws ManifoldCFException
+  {
+    ConfigurationNode connectionNode = findConfigurationNode(input,API_MAPPINGCONNECTIONNODE);
+    if (connectionNode == null)
+      throw new ManifoldCFException("Input argument must have '"+API_MAPPINGCONNECTIONNODE+"' field");
+      
+    // Turn the configuration node into an OutputConnection
+    org.apache.manifoldcf.authorities.mapping.MappingConnection mappingConnection = new org.apache.manifoldcf.authorities.mapping.MappingConnection();
+    processMappingConnection(mappingConnection,connectionNode);
+      
+    if (mappingConnection.getName() == null)
+      mappingConnection.setName(connectionName);
+    else
+    {
+      if (!mappingConnection.getName().equals(connectionName))
+        throw new ManifoldCFException("Connection name in path and in object must agree");
+    }
+      
+    try
+    {
+      // Save the connection.
+      IMappingConnectionManager connectionManager = MappingConnectionManagerFactory.make(tc);
+      if (connectionManager.save(mappingConnection))
+        return WRITERESULT_CREATED;
+    }
+    catch (ManifoldCFException e)
+    {
+      createErrorNode(output,e);
+    }
+    return WRITERESULT_FOUND;
+  }
+
   /** Write repository connection.
   */
   protected static int apiWriteRepositoryConnection(IThreadContext tc, Configuration output, Configuration input, String connectionName)
@@ -3467,6 +3650,11 @@ public class ManifoldCF extends org.apac
       String connectionName = decodeAPIPathElement(path.substring("outputconnections/".length()));
       return apiWriteOutputConnection(tc,output,input,connectionName);
     }
+    else if (path.startsWith("mappingconnections/"))
+    {
+      String connectionName = decodeAPIPathElement(path.substring("mappingconnections/".length()));
+      return apiWriteMappingConnection(tc,output,input,connectionName);
+    }
     else if (path.startsWith("authorityconnections/"))
     {
       String connectionName = decodeAPIPathElement(path.substring("authorityconnections/".length()));
@@ -4290,6 +4478,7 @@ public class ManifoldCF extends org.apac
   protected static final String CONNECTIONNODE_CLASSNAME = "class_name";
   protected static final String CONNECTIONNODE_MAXCONNECTIONS = "max_connections";
   protected static final String CONNECTIONNODE_DESCRIPTION = "description";
+  protected static final String CONNECTIONNODE_PREREQUISITE = "prerequisite";
   protected static final String CONNECTIONNODE_CONFIGURATION = "configuration";
   protected static final String CONNECTIONNODE_ACLAUTHORITY = "acl_authority";
   protected static final String CONNECTIONNODE_THROTTLE = "throttle";
@@ -4453,6 +4642,12 @@ public class ManifoldCF extends org.apac
           throw new ManifoldCFException("Error parsing max connections: "+e.getMessage(),e);
         }
       }
+      else if (childType.equals(CONNECTIONNODE_PREREQUISITE))
+      {
+        if (child.getValue() == null)
+          throw new ManifoldCFException("Connection prerequisite node requires a value");
+        connection.setPrerequisiteMapping(child.getValue());
+      }
       else if (childType.equals(CONNECTIONNODE_DESCRIPTION))
       {
         if (child.getValue() == null)
@@ -4478,7 +4673,8 @@ public class ManifoldCF extends org.apac
       throw new ManifoldCFException("Missing connection field: '"+CONNECTIONNODE_CLASSNAME+"'");
 
   }
-  
+
+
   /** Format an authority connection.
   */
   protected static void formatAuthorityConnection(ConfigurationNode connectionNode, IAuthorityConnection connection)
@@ -4502,6 +4698,138 @@ public class ManifoldCF extends org.apac
     child.setValue(Integer.toString(connection.getMaxConnections()));
     connectionNode.addChild(connectionNode.getChildCount(),child);
 
+    if (connection.getPrerequisiteMapping() != null)
+    {
+      child = new ConfigurationNode(CONNECTIONNODE_PREREQUISITE);
+      child.setValue(connection.getPrerequisiteMapping());
+      connectionNode.addChild(connectionNode.getChildCount(),child);
+    }
+
+    if (connection.getDescription() != null)
+    {
+      child = new ConfigurationNode(CONNECTIONNODE_DESCRIPTION);
+      child.setValue(connection.getDescription());
+      connectionNode.addChild(connectionNode.getChildCount(),child);
+    }
+    
+    ConfigParams cp = connection.getConfigParams();
+    child = new ConfigurationNode(CONNECTIONNODE_CONFIGURATION);
+    j = 0;
+    while (j < cp.getChildCount())
+    {
+      ConfigurationNode cn = cp.findChild(j++);
+      child.addChild(child.getChildCount(),cn);
+    }
+    connectionNode.addChild(connectionNode.getChildCount(),child);
+
+  }
+
+  // Mapping connection API methods
+  
+  /** Convert input hierarchy into an MappingConnection object.
+  */
+  protected static void processMappingConnection(org.apache.manifoldcf.authorities.mapping.MappingConnection connection, ConfigurationNode connectionNode)
+    throws ManifoldCFException
+  {
+    // Walk through the node's children
+    int i = 0;
+    while (i < connectionNode.getChildCount())
+    {
+      ConfigurationNode child = connectionNode.findChild(i++);
+      String childType = child.getType();
+      if (childType.equals(CONNECTIONNODE_ISNEW))
+      {
+        if (child.getValue() == null)
+          throw new ManifoldCFException("Connection isnew node requires a value");
+        connection.setIsNew(child.getValue().equals("true"));
+      }
+      else if (childType.equals(CONNECTIONNODE_NAME))
+      {
+        if (child.getValue() == null)
+          throw new ManifoldCFException("Connection name node requires a value");
+        connection.setName(child.getValue());
+      }
+      else if (childType.equals(CONNECTIONNODE_CLASSNAME))
+      {
+        if (child.getValue() == null)
+          throw new ManifoldCFException("Connection classname node requires a value");
+        connection.setClassName(child.getValue());
+      }
+      else if (childType.equals(CONNECTIONNODE_MAXCONNECTIONS))
+      {
+        if (child.getValue() == null)
+          throw new ManifoldCFException("Connection maxconnections node requires a value");
+        try
+        {
+          connection.setMaxConnections(Integer.parseInt(child.getValue()));
+        }
+        catch (NumberFormatException e)
+        {
+          throw new ManifoldCFException("Error parsing max connections: "+e.getMessage(),e);
+        }
+      }
+      else if (childType.equals(CONNECTIONNODE_PREREQUISITE))
+      {
+        if (child.getValue() == null)
+          throw new ManifoldCFException("Connection prerequisite node requires a value");
+        connection.setPrerequisiteMapping(child.getValue());
+      }
+      else if (childType.equals(CONNECTIONNODE_DESCRIPTION))
+      {
+        if (child.getValue() == null)
+          throw new ManifoldCFException("Connection description node requires a value");
+        connection.setDescription(child.getValue());
+      }
+      else if (childType.equals(CONNECTIONNODE_CONFIGURATION))
+      {
+        // Get the connection's configuration, clear out the children, and copy new ones from the child.
+        ConfigParams cp = connection.getConfigParams();
+        cp.clearChildren();
+        int j = 0;
+        while (j < child.getChildCount())
+        {
+          ConfigurationNode cn = child.findChild(j++);
+          cp.addChild(cp.getChildCount(),new ConfigNode(cn));
+        }
+      }
+      else
+        throw new ManifoldCFException("Unrecognized mapping connection field: '"+childType+"'");
+    }
+    if (connection.getClassName() == null)
+      throw new ManifoldCFException("Missing connection field: '"+CONNECTIONNODE_CLASSNAME+"'");
+
+  }
+
+  /** Format a mapping connection.
+  */
+  protected static void formatMappingConnection(ConfigurationNode connectionNode, IMappingConnection connection)
+  {
+    ConfigurationNode child;
+    int j;
+    
+    child = new ConfigurationNode(CONNECTIONNODE_ISNEW);
+    child.setValue(connection.getIsNew()?"true":"false");
+    connectionNode.addChild(connectionNode.getChildCount(),child);
+
+    child = new ConfigurationNode(CONNECTIONNODE_NAME);
+    child.setValue(connection.getName());
+    connectionNode.addChild(connectionNode.getChildCount(),child);
+
+    child = new ConfigurationNode(CONNECTIONNODE_CLASSNAME);
+    child.setValue(connection.getClassName());
+    connectionNode.addChild(connectionNode.getChildCount(),child);
+
+    child = new ConfigurationNode(CONNECTIONNODE_MAXCONNECTIONS);
+    child.setValue(Integer.toString(connection.getMaxConnections()));
+    connectionNode.addChild(connectionNode.getChildCount(),child);
+
+    if (connection.getPrerequisiteMapping() != null)
+    {
+      child = new ConfigurationNode(CONNECTIONNODE_PREREQUISITE);
+      child.setValue(connection.getPrerequisiteMapping());
+      connectionNode.addChild(connectionNode.getChildCount(),child);
+    }
+    
     if (connection.getDescription() != null)
     {
       child = new ConfigurationNode(CONNECTIONNODE_DESCRIPTION);

Modified: manifoldcf/branches/CONNECTORS-703/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_en_US.properties
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_en_US.properties?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_en_US.properties (original)
+++ manifoldcf/branches/CONNECTORS-703/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_en_US.properties Sun Jun 30 14:04:52 2013
@@ -181,7 +181,7 @@ editauthority.Throttling=Throttling
 editauthority.EditAuthorityConnection=Edit Authority Connection
 editauthority.Prerequisites=Prerequisites
 editauthority.PrerequisiteUserMappingColon=Prerequisite user mapping:
-editauthority.NoPrerequisites=-- No Prerequisites --
+editauthority.NoPrerequisites=(No Prerequisites)
 
 editmapper.ApacheManifoldCFEditMapping=Apache ManifoldCF: Edit Mapping
 editmapper.EditAMapping=Edit A Mapping
@@ -208,7 +208,7 @@ editmapper.Throttling=Throttling
 editmapper.EditMappingConnection=Edit Mapping Connection
 editmapper.Prerequisites=Prerequisites
 editmapper.PrerequisiteUserMappingColon=Prerequisite user mapping:
-editmapper.NoPrerequisites=-- No Prerequisites --
+editmapper.NoPrerequisites=(No Prerequisites)
 
 listconnections.ApacheManifoldCFListConnections=Apache ManifoldCF: List Connections
 listconnections.ListOfRepositoryConnections=List of Repository Connections

Modified: manifoldcf/branches/CONNECTORS-703/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_ja_JP.properties
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-703/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_ja_JP.properties?rev=1498125&r1=1498124&r2=1498125&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-703/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_ja_JP.properties (original)
+++ manifoldcf/branches/CONNECTORS-703/framework/ui-core/src/main/native2ascii/org/apache/manifoldcf/ui/i18n/common_ja_JP.properties Sun Jun 30 14:04:52 2013
@@ -181,7 +181,7 @@ editauthority.Throttling=スロã�
 editauthority.EditAuthorityConnection=Edit Authority Connection
 editauthority.Prerequisites=Prerequisites
 editauthority.PrerequisiteUserMappingColon=Prerequisite user mapping:
-editauthority.NoPrerequisites=-- No Prerequisites --
+editauthority.NoPrerequisites=(No Prerequisites)
 
 editmapper.ApacheManifoldCFEditMapping=Apache ManifoldCF: Edit Mapping
 editmapper.EditAMapping=Edit A Mapping
@@ -208,7 +208,7 @@ editmapper.Throttling=Throttling
 editmapper.EditMappingConnection=Edit Mapping Connection
 editmapper.Prerequisites=Prerequisites
 editmapper.PrerequisiteUserMappingColon=Prerequisite user mapping:
-editmapper.NoPrerequisites=-- No Prerequisites --
+editmapper.NoPrerequisites=(No Prerequisites)
 
 listconnections.ApacheManifoldCFListConnections=Apache ManifoldCF:コネクション一覧
 listconnections.ListOfRepositoryConnections=リポジトリコネクション一覧