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/05/16 13:35:14 UTC

svn commit: r1679731 [1/2] - in /manifoldcf/branches/dev_1x: ./ connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/

Author: kwright
Date: Sat May 16 11:35:14 2015
New Revision: 1679731

URL: http://svn.apache.org/r1679731
Log:
Pull up fix for CONNECTORS-1199 from trunk.

Modified:
    manifoldcf/branches/dev_1x/   (props changed)
    manifoldcf/branches/dev_1x/CHANGES.txt
    manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxClient.java
    manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxConfig.java
    manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxConnector.java
    manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxDocument.java
    manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxException.java

Propchange: manifoldcf/branches/dev_1x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sat May 16 11:35:14 2015
@@ -123,4 +123,4 @@
 /manifoldcf/branches/CONNECTORS-981:1605049-1605773
 /manifoldcf/branches/CONNECTORS-989:1611600-1612101
 /manifoldcf/branches/CONNECTORS-990:1610284-1610707
-/manifoldcf/trunk:1620703,1620748,1620812,1620862,1621449,1621613,1621855,1622213,1622740,1622850,1622853-1622854,1623249,1623251,1623314,1623599,1623951,1623953-1623954,1623956,1623972,1624058,1624085,1624174,1624236,1624377,1624384,1624399,1624449,1624464,1624504,1624729-1624731,1624906,1624909-1624910,1624982,1625023,1625095,1625103,1625108,1625264,1625270,1625394,1625400,1625910,1626090,1626097,1626102,1626638-1626639,1626973,1627687,1627690,1627959,1628046,1628066,1628106,1628168,1628188,1628699,1628798,1628808,1628845,1628905,1629122,1629374-1629375,1629379,1629541,1629994,1630188,1630535,1630623,1630671,1630812,1630885,1631039,1631162,1631164,1631252,1631750,1631953,1632013,1632225,1632289,1632562,1632844,1632847,1632854,1633062-1633063,1633108,1633193,1633202,1633282,1633284,1633295,1633336,1633339,1633345,1633348,1633364,1633378,1633383,1633432,1633546,1633590,1633634,1633668,1633727,1633760,1633764,1633786,1633910,1633923,1634021,1634028,1634067,1634132,1634145,1634148,163
 4155,1634188,1634202,1634264,1634373,1634530,1634688,1634850,1634857,1635103,1635116,1635421,1635438,1635478,1635481,1635484,1635490,1635809,1635939,1636146,1636167,1636180,1636207,1636215,1636232,1636334,1636519,1636570,1636684,1636940,1637011,1637310,1637350,1637364,1637373,1637378,1639259,1639593,1639600,1640018,1640101,1640199,1640204,1640208,1640314,1640319,1640749,1640772,1640805,1640888,1640925,1640941-1640942,1641222,1641328,1641557,1641559,1641629,1641633,1641724,1641754,1641911,1642163,1642255,1642318,1642531,1642650,1642658,1642673,1642716,1644197,1644399,1644538,1644920,1644931,1646317,1646397,1646403,1646408,1646640,1646947,1647574,1647585,1647608,1648686,1648976,1649201,1649203,1649529,1649605,1649628,1649794,1650351,1650722,1650741-1650742,1650745,1650747,1650911,1650954,1651332,1651539,1651907,1651921,1652071,1652974,1653175,1653899,1654651,1655205,1655261,1655264,1655377,1655411,1655618,1655914,1657346,1657443,1658004,1658036,1658121,1658155,1658188,1658463,1658476,
 1660258,1660276,1661454,1665848,1666160,1666781,1666820,1668312,1669100,1669238,1669487,1669523,1669586,1669660,1670614,1670625,1670715,1671496,1672169,1672301,1672616,1672737,1673559,1673573,1673579,1673722,1675781,1675898,1676094,1676882,1676910,1678300,1678329,1678471,1678551
+/manifoldcf/trunk:1620703,1620748,1620812,1620862,1621449,1621613,1621855,1622213,1622740,1622850,1622853-1622854,1623249,1623251,1623314,1623599,1623951,1623953-1623954,1623956,1623972,1624058,1624085,1624174,1624236,1624377,1624384,1624399,1624449,1624464,1624504,1624729-1624731,1624906,1624909-1624910,1624982,1625023,1625095,1625103,1625108,1625264,1625270,1625394,1625400,1625910,1626090,1626097,1626102,1626638-1626639,1626973,1627687,1627690,1627959,1628046,1628066,1628106,1628168,1628188,1628699,1628798,1628808,1628845,1628905,1629122,1629374-1629375,1629379,1629541,1629994,1630188,1630535,1630623,1630671,1630812,1630885,1631039,1631162,1631164,1631252,1631750,1631953,1632013,1632225,1632289,1632562,1632844,1632847,1632854,1633062-1633063,1633108,1633193,1633202,1633282,1633284,1633295,1633336,1633339,1633345,1633348,1633364,1633378,1633383,1633432,1633546,1633590,1633634,1633668,1633727,1633760,1633764,1633786,1633910,1633923,1634021,1634028,1634067,1634132,1634145,1634148,163
 4155,1634188,1634202,1634264,1634373,1634530,1634688,1634850,1634857,1635103,1635116,1635421,1635438,1635478,1635481,1635484,1635490,1635809,1635939,1636146,1636167,1636180,1636207,1636215,1636232,1636334,1636519,1636570,1636684,1636940,1637011,1637310,1637350,1637364,1637373,1637378,1639259,1639593,1639600,1640018,1640101,1640199,1640204,1640208,1640314,1640319,1640749,1640772,1640805,1640888,1640925,1640941-1640942,1641222,1641328,1641557,1641559,1641629,1641633,1641724,1641754,1641911,1642163,1642255,1642318,1642531,1642650,1642658,1642673,1642716,1644197,1644399,1644538,1644920,1644931,1646317,1646397,1646403,1646408,1646640,1646947,1647574,1647585,1647608,1648686,1648976,1649201,1649203,1649529,1649605,1649628,1649794,1650351,1650722,1650741-1650742,1650745,1650747,1650911,1650954,1651332,1651539,1651907,1651921,1652071,1652974,1653175,1653899,1654651,1655205,1655261,1655264,1655377,1655411,1655618,1655914,1657346,1657443,1658004,1658036,1658121,1658155,1658188,1658463,1658476,
 1660258,1660276,1661454,1665848,1666160,1666781,1666820,1668312,1669100,1669238,1669487,1669523,1669586,1669660,1670614,1670625,1670715,1671496,1672169,1672301,1672616,1672737,1673559,1673573,1673579,1673722,1675781,1675898,1676094,1676882,1676910,1678300,1678329,1678471,1678551,1679730

Modified: manifoldcf/branches/dev_1x/CHANGES.txt
URL: http://svn.apache.org/viewvc/manifoldcf/branches/dev_1x/CHANGES.txt?rev=1679731&r1=1679730&r2=1679731&view=diff
==============================================================================
--- manifoldcf/branches/dev_1x/CHANGES.txt (original)
+++ manifoldcf/branches/dev_1x/CHANGES.txt Sat May 16 11:35:14 2015
@@ -3,6 +3,9 @@ $Id$
 
 ======================= 1.10-dev =====================
 
+CONNECTORS-1199: SearchBlox connector formatting non-standard.
+(Karl Wright)
+
 CONNECTORS-1198: SearchBlox connector session management not
 working properly.
 (Timo Selvaraj, Rafa Haro, Karl Wright)

Modified: manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxClient.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxClient.java?rev=1679731&r1=1679730&r2=1679731&view=diff
==============================================================================
--- manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxClient.java (original)
+++ manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxClient.java Sat May 16 11:35:14 2015
@@ -47,222 +47,215 @@ import org.xml.sax.SAXException;
  */
 public class SearchBloxClient {
 
-    // TODO All this might need to be included in a configuration file
-    public static final String DEFAULT_ENDPOINT = "http://localhost:8080/searchblox/rest/v1/api";
+  // TODO All this might need to be included in a configuration file
+  public static final String DEFAULT_ENDPOINT = "http://localhost:8080/searchblox/rest/v1/api";
 
-    private static final String ADD_PATH = "add";
+  private static final String ADD_PATH = "add";
 
-    private static final String DELETE_PATH = "delete";
+  private static final String DELETE_PATH = "delete";
 
-    private static final String STATUS_PATH = "status";
+  private static final String STATUS_PATH = "status";
 
-    private static final String CREATE_PATH = "coladd";
-
-    private static final String CLEAR_PATH = "clear";
-
-    private static final String STATUS_NODE = "statuscode";
-    
-    private static final Pattern status_pattern = Pattern.compile("^status code\\s?:\\s([0-9]+)$");
-
-    public static enum ResponseCode {
-        DOCUMENT_INDEXED(100),
-        DOCUMENT_REJECTED(101),
-        DOCUMENT_DELETED(200, 2001),
-        DOCUMENT_NOT_EXIST(201, 2002),
-        DOCUMENT_NOT_FOUND(301),
-        COLLECTION_CLEARED(400),
-        ERROR_CLEARING_COLLECTION(401),
-        COLLECTION_CREATED(900),
-        INVALID_COLLECTION_NAME(500, 501),
-        INVALID_REQUEST(501),
-        INVALID_DOCUMENT_LOCATION(502),
-        NOT_CUSTOM_COLLECTION(503),
-        LIMIT_EXCEEDED(504),
-        INVALID_LICENSE_ID(601),
-        SERVER_UNREACHABLE(700);
-
-        private int code;
-        private int jsonCode;
-        
-        ResponseCode(int code) {
-            this.code = code;
-        }
-        
-        ResponseCode(int code, int jsonCode) {
-            this.code = code;
-            this.jsonCode = jsonCode;
-        }
-        
-        static ResponseCode getCodeFromValue(int value){
-        	for(ResponseCode e:ResponseCode.values())
-        		if(value == e.code)
-        			return e;
-        	return null;
-        }
-        
-        static ResponseCode getCodeFromValue(int value, boolean json){
-        	for(ResponseCode e:ResponseCode.values())
-        		if((json && value == e.jsonCode) || (value == e.code)) {
-        			return e;
-        		}
-        	return null;
-        }
-        
-        int getCode(){
-        	return code;
-        }
-        
-        int getJsonCode() {
-        	return jsonCode;
-        }
+  private static final String CREATE_PATH = "coladd";
+
+  private static final String CLEAR_PATH = "clear";
+
+  private static final String STATUS_NODE = "statuscode";
+  
+  private static final Pattern status_pattern = Pattern.compile("^status code\\s?:\\s([0-9]+)$");
+
+  public static enum ResponseCode {
+    DOCUMENT_INDEXED(100),
+    DOCUMENT_REJECTED(101),
+    DOCUMENT_DELETED(200, 2001),
+    DOCUMENT_NOT_EXIST(201, 2002),
+    DOCUMENT_NOT_FOUND(301),
+    COLLECTION_CLEARED(400),
+    ERROR_CLEARING_COLLECTION(401),
+    COLLECTION_CREATED(900),
+    INVALID_COLLECTION_NAME(500, 501),
+    INVALID_REQUEST(501),
+    INVALID_DOCUMENT_LOCATION(502),
+    NOT_CUSTOM_COLLECTION(503),
+    LIMIT_EXCEEDED(504),
+    INVALID_LICENSE_ID(601),
+    SERVER_UNREACHABLE(700);
+
+    private int code;
+    private int jsonCode;
+    
+    ResponseCode(int code) {
+      this.code = code;
     }
     
-
-    private String apikey;
-    private Client client;
-    private UriBuilder uriBuilder;
-
-    public SearchBloxClient(String apikey, ClientBuilder builder, String endpoint) {
-        this.apikey = apikey;
-        builder.register(StringTextStar.class);
-        this.client = builder.build();
-        if (endpoint != null && !endpoint.isEmpty()) {
-            uriBuilder = UriBuilder.fromUri(endpoint);
-        } else {
-            uriBuilder = UriBuilder.fromUri(DEFAULT_ENDPOINT);
+    ResponseCode(int code, int jsonCode) {
+      this.code = code;
+      this.jsonCode = jsonCode;
+    }
+    
+    static ResponseCode getCodeFromValue(int value){
+        for(ResponseCode e:ResponseCode.values())
+            if(value == e.code)
+                return e;
+        return null;
+    }
+    
+    static ResponseCode getCodeFromValue(int value, boolean json){
+      for(ResponseCode e:ResponseCode.values())
+        if((json && value == e.jsonCode) || (value == e.code)) {
+          return e;
         }
+      return null;
+    }
+    
+    int getCode(){
+      return code;
+    }
+    
+    int getJsonCode() {
+      return jsonCode;
     }
+  }
+  
 
+  private String apikey;
+  private Client client;
+  private UriBuilder uriBuilder;
+
+  public SearchBloxClient(String apikey, ClientBuilder builder, String endpoint) {
+    this.apikey = apikey;
+    builder.register(StringTextStar.class);
+    this.client = builder.build();
+    if (endpoint != null && !endpoint.isEmpty()) {
+      uriBuilder = UriBuilder.fromUri(endpoint);
+    } else {
+      uriBuilder = UriBuilder.fromUri(DEFAULT_ENDPOINT);
+    }
+  }
+
+
+  public ResponseCode addUpdateDocument(SearchBloxDocument document, String format)
+      throws SearchBloxException {
+    return post(document, format, SearchBloxDocument.DocumentAction.ADD_UPDATE);
+  }
+
+  public ResponseCode deleteDocument(SearchBloxDocument document, String format)
+      throws SearchBloxException {
+    return post(document, format, SearchBloxDocument.DocumentAction.DELETE);
+  }
+
+  public ResponseCode createCollection(String colname, String format)
+      throws SearchBloxException {
+    SearchBloxDocument document = new SearchBloxDocument(apikey);
+    document.colName = colname;
+    return post(document, format, SearchBloxDocument.DocumentAction.CREATE);
+  }
+
+  public ResponseCode clearCollection(String colname, String format)
+      throws SearchBloxException {
+    SearchBloxDocument document = new SearchBloxDocument(apikey);
+    document.colName = colname;
+    return post(document, format, SearchBloxDocument.DocumentAction.CLEAR);
+  }
+
+  public boolean ping(String format)
+      throws SearchBloxException {
+    SearchBloxDocument document = new SearchBloxDocument(apikey);
+    document.colName = UUID.randomUUID().toString();
+    document.uid = UUID.randomUUID().toString();
+    ResponseCode result = post(document, format, SearchBloxDocument.DocumentAction.STATUS);
+    return result == ResponseCode.INVALID_COLLECTION_NAME;
+  }
 
-    public ResponseCode addUpdateDocument(SearchBloxDocument document, String format)
-            throws SearchBloxException {
-        return post(document, format, SearchBloxDocument.DocumentAction.ADD_UPDATE);
-    }
-
-    public ResponseCode deleteDocument(SearchBloxDocument document, String format)
-            throws SearchBloxException {
-        return post(document, format, SearchBloxDocument.DocumentAction.DELETE);
-    }
-
-    public ResponseCode createCollection(String colname, String format)
-            throws SearchBloxException {
-        SearchBloxDocument document = new SearchBloxDocument(apikey);
-        document.colName = colname;
-        return post(document, format, SearchBloxDocument.DocumentAction.CREATE);
-    }
-
-    public ResponseCode clearCollection(String colname, String format)
-            throws SearchBloxException {
-        SearchBloxDocument document = new SearchBloxDocument(apikey);
-        document.colName = colname;
-        return post(document, format, SearchBloxDocument.DocumentAction.CLEAR);
-    }
-
-    public boolean ping(String format)
-            throws SearchBloxException {
-        SearchBloxDocument document = new SearchBloxDocument(apikey);
-        document.colName = UUID.randomUUID().toString();
-        document.uid = UUID.randomUUID().toString();
-        ResponseCode result = post(document, format, SearchBloxDocument.DocumentAction.STATUS);
-        return result == ResponseCode.INVALID_COLLECTION_NAME;
-    }
-
-    private ResponseCode post(SearchBloxDocument document, String format, SearchBloxDocument.DocumentAction action)
-            throws SearchBloxException {
-        
-    	SearchBloxDocument.IndexingFormat iFormat = SearchBloxDocument.IndexingFormat.valueOf(format.toUpperCase());
-    	
-    	if (iFormat == null) {
-            Logging.connectors.error("[Post request] Format not recognized " +format);
-            throw new SearchBloxException("Unknown Serialization Format " + format);
-        }
-    	
-    	boolean isJson = iFormat.equals(SearchBloxDocument.IndexingFormat.JSON);
-    	
-        
-
-        UriBuilder uri = uriBuilder.clone();
-        if (action == SearchBloxDocument.DocumentAction.ADD_UPDATE) {
-            uri = uri.path(ADD_PATH);
-        } else if (action == SearchBloxDocument.DocumentAction.DELETE) {
-            uri = uri.path(DELETE_PATH);
-        } else if (action == SearchBloxDocument.DocumentAction.STATUS) {
-            uri = uri.path(STATUS_PATH);
-        } else if (action == SearchBloxDocument.DocumentAction.CREATE) {
-            uri = uri.path(CREATE_PATH);
-        } else if (action == SearchBloxDocument.DocumentAction.CLEAR) {
-            uri = uri.path(CLEAR_PATH);
-        }
+  private ResponseCode post(SearchBloxDocument document, String format, SearchBloxDocument.DocumentAction action)
+      throws SearchBloxException {
+    
+    SearchBloxDocument.IndexingFormat iFormat = SearchBloxDocument.IndexingFormat.valueOf(format.toUpperCase());
+      
+    if (iFormat == null) {
+      Logging.connectors.error("[Post request] Format not recognized " +format);
+      throw new SearchBloxException("Unknown Serialization Format " + format);
+    }
+      
+    boolean isJson = iFormat.equals(SearchBloxDocument.IndexingFormat.JSON);
+      
+    
 
-        WebTarget target = client.target(uri.build());
-        Builder httpRequest = target.request();
-        if (iFormat == SearchBloxDocument.IndexingFormat.JSON) {
-        	httpRequest.accept(MediaType.APPLICATION_JSON_TYPE);
-        }else{
-        	httpRequest.accept(MediaType.APPLICATION_XML_TYPE);
-        }
-        
+    UriBuilder uri = uriBuilder.clone();
+    if (action == SearchBloxDocument.DocumentAction.ADD_UPDATE) {
+      uri = uri.path(ADD_PATH);
+    } else if (action == SearchBloxDocument.DocumentAction.DELETE) {
+      uri = uri.path(DELETE_PATH);
+    } else if (action == SearchBloxDocument.DocumentAction.STATUS) {
+      uri = uri.path(STATUS_PATH);
+    } else if (action == SearchBloxDocument.DocumentAction.CREATE) {
+      uri = uri.path(CREATE_PATH);
+    } else if (action == SearchBloxDocument.DocumentAction.CLEAR) {
+      uri = uri.path(CLEAR_PATH);
+    }
+
+    WebTarget target = client.target(uri.build());
+    Builder httpRequest = target.request();
+    if (iFormat == SearchBloxDocument.IndexingFormat.JSON) {
+      httpRequest.accept(MediaType.APPLICATION_JSON_TYPE);
+    }else{
+      httpRequest.accept(MediaType.APPLICATION_XML_TYPE);
+    }
+    
 
-        document.apiKey = this.apikey;
-        
-        String body = document.toString(iFormat, action);
-        Logging.connectors.debug("Document for document: " + document.uid +":" + body);
-        MediaType type = MediaType.TEXT_PLAIN_TYPE;
-        if (iFormat == SearchBloxDocument.IndexingFormat.JSON) {
-            type = MediaType.APPLICATION_JSON_TYPE;
-        }
+    document.apiKey = this.apikey;
+    
+    String body = document.toString(iFormat, action);
+    Logging.connectors.debug("Document for document: " + document.uid +":" + body);
+    MediaType type = MediaType.TEXT_PLAIN_TYPE;
+    if (iFormat == SearchBloxDocument.IndexingFormat.JSON) {
+      type = MediaType.APPLICATION_JSON_TYPE;
+    }
 
-        
-        Entity<String> entity = Entity.entity(body, type);
-        Response response = null;
-        try {
-        	response = httpRequest.post(entity);
-        }
-        catch(Exception e) {
-        //	return e.getCause() instanceof ConnectException ? ResponseCode.SERVER_UNREACHABLE : ResponseCode.INVALID_COLLECTION_NAME;
-            Logging.connectors.error("[No Connection] Error trying to connect ",e);
-            return ResponseCode.SERVER_UNREACHABLE;
-        }
-        
-        String rawResponse = response.readEntity(String.class);
-        if(iFormat == IndexingFormat.XML){
-        	DOMParser parser = new DOMParser();
-        	try {
-        		parser.parse(new InputSource(new StringReader(rawResponse)));
-        	} catch (SAXException | IOException e) {
-        		Logging.connectors.error("[Response parsing] Dom parsing error", e);
-        		throw new SearchBloxException(e);
-        	}
-        	Document doc = parser.getDocument();
-        	NodeList nodeList = doc.getElementsByTagName(STATUS_NODE);
-        	if (nodeList == null || nodeList.getLength() == 0) {
-        		String message = "[Response Parsing] Status code not found";
-        		Logging.connectors.error(message);
-        		throw new SearchBloxException(message);
-        	}
-        	String codeStr = nodeList.item(0).getTextContent();
-        	int statusCode = Integer.parseInt(codeStr);
-        	return ResponseCode.getCodeFromValue(statusCode, isJson);
-        }else{
-//        	try {
-//				JSONObject json = new JSONObject(rawResponse);
-//				String codeStr = json.getString(STATUS_NODE);
-        		Matcher matcher = status_pattern.matcher(rawResponse);
-        		String codeStr = null;
-        		if(matcher.find())
-        			codeStr = matcher.group(1);
-        		if(codeStr == null){
-        			String message = "[Response parsing] Response code parsing error";
-        			Logging.connectors.error(message);
-            		throw new SearchBloxException(message);
-        		}
-        			
-				int statusCode = Integer.parseInt(codeStr);
-	        	return ResponseCode.getCodeFromValue(statusCode, isJson);
-//			} catch (JSONException e) {
-//				Logging.connectors.error("[Response parsing] Response JSON parsing error", e);
-//        		throw new SearchBloxException(e);
-//			}
-        }
+    
+    Entity<String> entity = Entity.entity(body, type);
+    Response response = null;
+    try {
+      response = httpRequest.post(entity);
+    }
+    catch(Exception e) {
+    //    return e.getCause() instanceof ConnectException ? ResponseCode.SERVER_UNREACHABLE : ResponseCode.INVALID_COLLECTION_NAME;
+      Logging.connectors.error("[No Connection] Error trying to connect ",e);
+      return ResponseCode.SERVER_UNREACHABLE;
+    }
+    
+    String rawResponse = response.readEntity(String.class);
+    if(iFormat == IndexingFormat.XML){
+      DOMParser parser = new DOMParser();
+      try {
+        parser.parse(new InputSource(new StringReader(rawResponse)));
+      } catch (SAXException | IOException e) {
+        Logging.connectors.error("[Response parsing] Dom parsing error", e);
+        throw new SearchBloxException(e);
+      }
+      Document doc = parser.getDocument();
+      NodeList nodeList = doc.getElementsByTagName(STATUS_NODE);
+      if (nodeList == null || nodeList.getLength() == 0) {
+        String message = "[Response Parsing] Status code not found";
+        Logging.connectors.error(message);
+        throw new SearchBloxException(message);
+      }
+      String codeStr = nodeList.item(0).getTextContent();
+      int statusCode = Integer.parseInt(codeStr);
+      return ResponseCode.getCodeFromValue(statusCode, isJson);
+    }else{
+      Matcher matcher = status_pattern.matcher(rawResponse);
+      String codeStr = null;
+      if(matcher.find())
+        codeStr = matcher.group(1);
+      if(codeStr == null){
+        String message = "[Response parsing] Response code parsing error";
+        Logging.connectors.error(message);
+        throw new SearchBloxException(message);
+      }
+                
+      int statusCode = Integer.parseInt(codeStr);
+      return ResponseCode.getCodeFromValue(statusCode, isJson);
     }
+  }
 }

Modified: manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxConfig.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxConfig.java?rev=1679731&r1=1679730&r2=1679731&view=diff
==============================================================================
--- manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxConfig.java (original)
+++ manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxConfig.java Sat May 16 11:35:14 2015
@@ -7,12 +7,12 @@ package org.apache.manifoldcf.agents.out
  */
 class SearchBloxConfig {
 
-	static final String NODE_CONFIGURATION = "configuration";
-	static final String ATTRIBUTE_TITLEBOOST = "title_boost";
-	static final String ATTRIBUTE_CONTENTBOOST = "content_boost";
-	static final String ATTRIBUTE_KEYWORDSBOOST = "keywords_boost";
-	static final String ATTRIBUTE_DESCRIPTIONBOOST = "description_boost";
-	static final String ATTRIBUTE_INDEX_FORMAT = "indexformat";
-	static final String ATTRIBUTE_COLLECTION_NAME = "collection";
+  static final String NODE_CONFIGURATION = "configuration";
+  static final String ATTRIBUTE_TITLEBOOST = "title_boost";
+  static final String ATTRIBUTE_CONTENTBOOST = "content_boost";
+  static final String ATTRIBUTE_KEYWORDSBOOST = "keywords_boost";
+  static final String ATTRIBUTE_DESCRIPTIONBOOST = "description_boost";
+  static final String ATTRIBUTE_INDEX_FORMAT = "indexformat";
+  static final String ATTRIBUTE_COLLECTION_NAME = "collection";
 
 }

Modified: manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxConnector.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxConnector.java?rev=1679731&r1=1679730&r2=1679731&view=diff
==============================================================================
--- manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxConnector.java (original)
+++ manifoldcf/branches/dev_1x/connectors/searchblox/connector/src/main/java/org/apache/manifoldcf/agents/output/searchblox/SearchBloxConnector.java Sat May 16 11:35:14 2015
@@ -43,799 +43,799 @@ import java.util.concurrent.TimeUnit;
  */
 public class SearchBloxConnector extends BaseOutputConnector {
 
-	private final static String SEARCHBLOX_TAB_PARAMETERS = "SearchBloxConnector.Parameters";
+  private final static String SEARCHBLOX_TAB_PARAMETERS = "SearchBloxConnector.Parameters";
 
-	private static final String EDIT_SPECIFICATION_JS = "editSpecification.js";
-	private static final String EDIT_SPECIFICATION_CONFIGURATION_HTML = "editSpecification_Configuration.html";
-	private static final String VIEW_SPECIFICATION_HTML = "viewSpecification.html";
-
-	/** Forward to the javascript to check the configuration parameters */
-	private static final String EDIT_CONFIG_HEADER_FORWARD = "editConfiguration.js";
-
-	/** Forward to the HTML template to edit the configuration parameters */
-	private static final String EDIT_CONFIG_FORWARD_PARAMETERS = "editConfiguration_Parameters.html";
-
-	/** Forward to the HTML template to view the configuration parameters */
-	private static final String VIEW_CONFIG_FORWARD = "viewConfiguration.html";
-
-	/**
-	 * Default collection name
-	 */
-	private static final String DEFAULT_COLLECTION = "Custom";
-	
-	/**
-	 * Default apiKey
-	 */
-	private static final String DEFAULT_APIKEY = "apiKey";
-	
-	/**
-	 * Ingestion activity
-	 */
-	public final static String INGEST_ACTIVITY = "document ingest";
-
-	/**
-	 * Document removal activity
-	 */
-	public final static String REMOVE_ACTIVITY = "document deletion";
-
-	/**
-	 * Collection Creation activity
-	 */
-	public final static String CREATION_ACTIVITY = "collection created";
-
-	
-	private static final String SEARCHBLOX_ENDPOINT = "endpoint";
-	private static final String SEARCHBLOX_INDEXING_FORMAT = "indexformat";
-	private static final String SEARCHBLOX_SOCKET_TIMEOUT = "sockettimeout";
-	private static final String SEARCHBLOX_CONNECTION_TIMEOUT = "connectiontimeout";
-	
-	private static final String BUILDER_DEFAULT_SOCKET_TIMEOUT = "60";
-	private static final String BUILDER_DEFAULT_CONNECTION_TIMEOUT = "60";
-
-	private SearchBloxClient client = null;
-	private String apiKey = null;
-
-	public SearchBloxConnector() {
-
-	}
-
-	/** Connect.
-	*/
-	@Override
-	public void connect(ConfigParams configParams) {
-		super.connect(configParams);
-	}
-	
-	/**
-	 * This method is called to assess whether to count this connector instance
-	 * should actually be counted as being connected.
-	 *
-	 * @return true if the connector instance is actually connected.
-	 */
-	@Override
-	public boolean isConnected() {
-		return client != null;
-	}
-
-	/**
-	 * Close the connection. Call this before discarding the connection.
-	 */
-	@Override
-	public void disconnect() throws ManifoldCFException {
-		if (client != null) {
-			apiKey = null;
-			client = null;
-		}
-		super.disconnect();
-	}
-
-	/**
-	 * Return the list of activities that this connector supports (i.e. writes
-	 * into the log).
-	 *
-	 * @return the list.
-	 */
-	@Override
-	public String[] getActivitiesList() {
-		return new String[] { INGEST_ACTIVITY, REMOVE_ACTIVITY,
-				CREATION_ACTIVITY };
-	}
-
-	protected void getSession()
-		throws ManifoldCFException {
-		if (client == null) {
-			String connectionTimeoutString = params.getParameter(SEARCHBLOX_CONNECTION_TIMEOUT);
-			if (connectionTimeoutString == null)
-				connectionTimeoutString = BUILDER_DEFAULT_CONNECTION_TIMEOUT;
-			long connectionTimeout;
-			try {
-				connectionTimeout = Integer.parseInt(connectionTimeoutString);
-			} catch (NumberFormatException e) {
-				throw new ManifoldCFException("Bad connection timeout: "+e.getMessage(),e);
-			}
-			String socketTimeoutString = params.getParameter(SEARCHBLOX_SOCKET_TIMEOUT);
-			if (socketTimeoutString == null)
-				socketTimeoutString = BUILDER_DEFAULT_SOCKET_TIMEOUT;
-			long socketTimeout;
-			try {
-				socketTimeout = Integer.parseInt(socketTimeoutString);
-			} catch (NumberFormatException e) {
-				throw new ManifoldCFException("Bad socket timeout: "+e.getMessage(),e);
-			}
-			final String endpoint = params.getParameter(SEARCHBLOX_ENDPOINT);
-			this.apiKey = params.getParameter(SearchBloxDocument.API_KEY);
-			ResteasyClientBuilder builder = new ResteasyClientBuilder();
-			builder.connectionPoolSize(1);
-			builder.establishConnectionTimeout(connectionTimeout, TimeUnit.SECONDS);
-			builder.socketTimeout(socketTimeout, TimeUnit.SECONDS);
-			client = new SearchBloxClient(apiKey, builder, endpoint);
-		}
-		
-	}
-
-	@Override
-	public String check() throws ManifoldCFException {
-		getSession();
-		try {
-			String format = getConfiguration().getParameter(SEARCHBLOX_INDEXING_FORMAT);
-			if (client.ping(format)) {
-				return super.check();
-			} else {
-				return "Connection Not Working!. Check SearchBlox Server is up and the configuration is correct.";
-			}
-		} catch (SearchBloxException e) {
-			Logging.connectors.error("Connection Not Working", e);
-			return "Connection Not Working!" + e.getMessage();
-		}
-	}
-
-	/**
-	 * Get an output version string, given an output specification. The output
-	 * version string is used to uniquely describe the pertinent details of the
-	 * output specification and the configuration, to allow the Connector
-	 * Framework to determine whether a document will need to be output again.
-	 * Note that the contents of the document cannot be considered by this
-	 * method, and that a different version string (defined in
-	 * IRepositoryConnector) is used to describe the version of the actual
-	 * document.
-	 * <p/>
-	 * This method presumes that the connector object has been configured, and
-	 * it is thus able to communicate with the output data store should that be
-	 * necessary.
-	 *
-	 * @param spec
-	 *            is the current output specification for the job that is doing
-	 *            the crawling.
-	 * @return a string, of unlimited length, which uniquely describes output
-	 *         configuration and specification in such a way that if two such
-	 *         strings are equal, the document will not need to be sent again to
-	 *         the output data store.
-	 */
-	@Override
-	public VersionContext getPipelineDescription(Specification spec)
-			throws ManifoldCFException, ServiceInterruption {
-		SpecPacker sp = new SpecPacker(spec);
-		return new VersionContext(sp.toPackedString(), params, spec);
-	}
-
-	/**
-	 * Detect if a mime type is indexable or not. This method is used by
-	 * participating repository connectors to pre-filter the number of unusable
-	 * documents that will be passed to this output connector.
-	 *
-	 * @param outputDescription
-	 *            is the document's output version.
-	 * @param mimeType
-	 *            is the mime type of the document.
-	 * @return true if the mime type is indexable by this connector.
-	 */
-	@Override
-	public boolean checkMimeTypeIndexable(VersionContext outputDescription,
-			String mimeType, IOutputCheckActivity activities)
-			throws ManifoldCFException, ServiceInterruption {
-		// We work against the API, so we need to suppose the content reached by
-		// the connector is a String convertible stream
-		return true;
-	}
-
-	/**
-	 * Pre-determine whether a document's length is indexable by this connector.
-	 * This method is used by participating repository connectors to help filter
-	 * out documents that are too long to be indexable.
-	 *
-	 * @param outputDescription
-	 *            is the document's output version.
-	 * @param length
-	 *            is the length of the document.
-	 * @return true if the file is indexable.
-	 */
-	@Override
-	public boolean checkLengthIndexable(VersionContext outputDescription,
-			long length, IOutputCheckActivity activities)
-			throws ManifoldCFException, ServiceInterruption {
-		// No Size Limit for SearchBlox
-		return true;
-	}
-
-	/**
-	 * Add (or replace) a document in the output data store using the connector.
-	 * This method presumes that the connector object has been configured, and
-	 * it is thus able to communicate with the output data store should that be
-	 * necessary.
-	 *
-	 * @param documentURI
-	 *            is the URI of the document. The URI is presumed to be the
-	 *            unique identifier which the output data store will use to
-	 *            process and serve the document. This URI is constructed by the
-	 *            repository connector which fetches the document, and is thus
-	 *            universal across all output connectors.
-	 * @param pipelineDescription
-	 *            includes the description string that was constructed for this
-	 *            document by the getOutputDescription() method.
-	 * @param document
-	 *            is the document data to be processed (handed to the output
-	 *            data store).
-	 * @param authorityNameString
-	 *            is the name of the authority responsible for authorizing any
-	 *            access tokens passed in with the repository document. May be
-	 *            null.
-	 * @param activities
-	 *            is the handle to an object that the implementer of a pipeline
-	 *            connector may use to perform operations, such as logging
-	 *            processing activity, or sending a modified document to the
-	 *            next stage in the pipeline.
-	 * @return the document status (accepted or permanently rejected).
-	 * @throws IOException
-	 *             only if there's a stream error reading the document data.
-	 */
-	@Override
-	public int addOrReplaceDocumentWithException(String documentURI,
-			VersionContext pipelineDescription, RepositoryDocument document,
-			String authorityNameString, IOutputAddActivity activities)
-			throws ManifoldCFException, ServiceInterruption, IOException {
-
-		Logging.connectors.info("Indexing Document " + documentURI);
-		long indexingTime = System.currentTimeMillis();
-		SpecPacker sp = new SpecPacker(pipelineDescription.getSpecification());
-		Map<String, List<String>> args = sp.getArgs();
-		// Establish a session
-		getSession();
-
-		SearchBloxDocument sbDoc = new SearchBloxDocument(this.apiKey,
-				documentURI, document, args);
-		String format = this.getConfiguration().getParameter(SEARCHBLOX_INDEXING_FORMAT);
-		long startTime = System.currentTimeMillis();
-		try {
-			ResponseCode code = client.addUpdateDocument(sbDoc, format);
-			if (code == ResponseCode.DOCUMENT_INDEXED) {
+  private static final String EDIT_SPECIFICATION_JS = "editSpecification.js";
+  private static final String EDIT_SPECIFICATION_CONFIGURATION_HTML = "editSpecification_Configuration.html";
+  private static final String VIEW_SPECIFICATION_HTML = "viewSpecification.html";
+
+  /** Forward to the javascript to check the configuration parameters */
+  private static final String EDIT_CONFIG_HEADER_FORWARD = "editConfiguration.js";
+
+  /** Forward to the HTML template to edit the configuration parameters */
+  private static final String EDIT_CONFIG_FORWARD_PARAMETERS = "editConfiguration_Parameters.html";
+
+  /** Forward to the HTML template to view the configuration parameters */
+  private static final String VIEW_CONFIG_FORWARD = "viewConfiguration.html";
+
+  /**
+   * Default collection name
+   */
+  private static final String DEFAULT_COLLECTION = "Custom";
+  
+  /**
+   * Default apiKey
+   */
+  private static final String DEFAULT_APIKEY = "apiKey";
+  
+  /**
+   * Ingestion activity
+   */
+  public final static String INGEST_ACTIVITY = "document ingest";
+
+  /**
+   * Document removal activity
+   */
+  public final static String REMOVE_ACTIVITY = "document deletion";
+
+  /**
+   * Collection Creation activity
+   */
+  public final static String CREATION_ACTIVITY = "collection created";
+
+  
+  private static final String SEARCHBLOX_ENDPOINT = "endpoint";
+  private static final String SEARCHBLOX_INDEXING_FORMAT = "indexformat";
+  private static final String SEARCHBLOX_SOCKET_TIMEOUT = "sockettimeout";
+  private static final String SEARCHBLOX_CONNECTION_TIMEOUT = "connectiontimeout";
+  
+  private static final String BUILDER_DEFAULT_SOCKET_TIMEOUT = "60";
+  private static final String BUILDER_DEFAULT_CONNECTION_TIMEOUT = "60";
+
+  private SearchBloxClient client = null;
+  private String apiKey = null;
+
+  public SearchBloxConnector() {
+
+  }
+
+  /** Connect.
+  */
+  @Override
+  public void connect(ConfigParams configParams) {
+    super.connect(configParams);
+  }
+  
+  /**
+   * This method is called to assess whether to count this connector instance
+   * should actually be counted as being connected.
+   *
+   * @return true if the connector instance is actually connected.
+   */
+  @Override
+  public boolean isConnected() {
+    return client != null;
+  }
+
+  /**
+   * Close the connection. Call this before discarding the connection.
+   */
+  @Override
+  public void disconnect() throws ManifoldCFException {
+    if (client != null) {
+      apiKey = null;
+      client = null;
+    }
+    super.disconnect();
+  }
+
+  /**
+   * Return the list of activities that this connector supports (i.e. writes
+   * into the log).
+   *
+   * @return the list.
+   */
+  @Override
+  public String[] getActivitiesList() {
+    return new String[] { INGEST_ACTIVITY, REMOVE_ACTIVITY,
+        CREATION_ACTIVITY };
+  }
+
+  protected void getSession()
+    throws ManifoldCFException {
+    if (client == null) {
+      String connectionTimeoutString = params.getParameter(SEARCHBLOX_CONNECTION_TIMEOUT);
+      if (connectionTimeoutString == null)
+        connectionTimeoutString = BUILDER_DEFAULT_CONNECTION_TIMEOUT;
+      long connectionTimeout;
+      try {
+        connectionTimeout = Integer.parseInt(connectionTimeoutString);
+      } catch (NumberFormatException e) {
+        throw new ManifoldCFException("Bad connection timeout: "+e.getMessage(),e);
+      }
+      String socketTimeoutString = params.getParameter(SEARCHBLOX_SOCKET_TIMEOUT);
+      if (socketTimeoutString == null)
+        socketTimeoutString = BUILDER_DEFAULT_SOCKET_TIMEOUT;
+      long socketTimeout;
+      try {
+        socketTimeout = Integer.parseInt(socketTimeoutString);
+      } catch (NumberFormatException e) {
+        throw new ManifoldCFException("Bad socket timeout: "+e.getMessage(),e);
+      }
+      final String endpoint = params.getParameter(SEARCHBLOX_ENDPOINT);
+      this.apiKey = params.getParameter(SearchBloxDocument.API_KEY);
+      ResteasyClientBuilder builder = new ResteasyClientBuilder();
+      builder.connectionPoolSize(1);
+      builder.establishConnectionTimeout(connectionTimeout, TimeUnit.SECONDS);
+      builder.socketTimeout(socketTimeout, TimeUnit.SECONDS);
+      client = new SearchBloxClient(apiKey, builder, endpoint);
+    }
+    
+  }
+
+  @Override
+  public String check() throws ManifoldCFException {
+    getSession();
+    try {
+      String format = getConfiguration().getParameter(SEARCHBLOX_INDEXING_FORMAT);
+      if (client.ping(format)) {
+        return super.check();
+      } else {
+        return "Connection Not Working!. Check SearchBlox Server is up and the configuration is correct.";
+      }
+    } catch (SearchBloxException e) {
+      Logging.connectors.error("Connection Not Working", e);
+      return "Connection Not Working!" + e.getMessage();
+    }
+  }
+
+  /**
+   * Get an output version string, given an output specification. The output
+   * version string is used to uniquely describe the pertinent details of the
+   * output specification and the configuration, to allow the Connector
+   * Framework to determine whether a document will need to be output again.
+   * Note that the contents of the document cannot be considered by this
+   * method, and that a different version string (defined in
+   * IRepositoryConnector) is used to describe the version of the actual
+   * document.
+   * <p/>
+   * This method presumes that the connector object has been configured, and
+   * it is thus able to communicate with the output data store should that be
+   * necessary.
+   *
+   * @param spec
+   *            is the current output specification for the job that is doing
+   *            the crawling.
+   * @return a string, of unlimited length, which uniquely describes output
+   *         configuration and specification in such a way that if two such
+   *         strings are equal, the document will not need to be sent again to
+   *         the output data store.
+   */
+  @Override
+  public VersionContext getPipelineDescription(Specification spec)
+      throws ManifoldCFException, ServiceInterruption {
+    SpecPacker sp = new SpecPacker(spec);
+    return new VersionContext(sp.toPackedString(), params, spec);
+  }
+
+  /**
+   * Detect if a mime type is indexable or not. This method is used by
+   * participating repository connectors to pre-filter the number of unusable
+   * documents that will be passed to this output connector.
+   *
+   * @param outputDescription
+   *            is the document's output version.
+   * @param mimeType
+   *            is the mime type of the document.
+   * @return true if the mime type is indexable by this connector.
+   */
+  @Override
+  public boolean checkMimeTypeIndexable(VersionContext outputDescription,
+      String mimeType, IOutputCheckActivity activities)
+      throws ManifoldCFException, ServiceInterruption {
+    // We work against the API, so we need to suppose the content reached by
+    // the connector is a String convertible stream
+    return true;
+  }
+
+  /**
+   * Pre-determine whether a document's length is indexable by this connector.
+   * This method is used by participating repository connectors to help filter
+   * out documents that are too long to be indexable.
+   *
+   * @param outputDescription
+   *            is the document's output version.
+   * @param length
+   *            is the length of the document.
+   * @return true if the file is indexable.
+   */
+  @Override
+  public boolean checkLengthIndexable(VersionContext outputDescription,
+      long length, IOutputCheckActivity activities)
+      throws ManifoldCFException, ServiceInterruption {
+    // No Size Limit for SearchBlox
+    return true;
+  }
+
+  /**
+   * Add (or replace) a document in the output data store using the connector.
+   * This method presumes that the connector object has been configured, and
+   * it is thus able to communicate with the output data store should that be
+   * necessary.
+   *
+   * @param documentURI
+   *            is the URI of the document. The URI is presumed to be the
+   *            unique identifier which the output data store will use to
+   *            process and serve the document. This URI is constructed by the
+   *            repository connector which fetches the document, and is thus
+   *            universal across all output connectors.
+   * @param pipelineDescription
+   *            includes the description string that was constructed for this
+   *            document by the getOutputDescription() method.
+   * @param document
+   *            is the document data to be processed (handed to the output
+   *            data store).
+   * @param authorityNameString
+   *            is the name of the authority responsible for authorizing any
+   *            access tokens passed in with the repository document. May be
+   *            null.
+   * @param activities
+   *            is the handle to an object that the implementer of a pipeline
+   *            connector may use to perform operations, such as logging
+   *            processing activity, or sending a modified document to the
+   *            next stage in the pipeline.
+   * @return the document status (accepted or permanently rejected).
+   * @throws IOException
+   *             only if there's a stream error reading the document data.
+   */
+  @Override
+  public int addOrReplaceDocumentWithException(String documentURI,
+      VersionContext pipelineDescription, RepositoryDocument document,
+      String authorityNameString, IOutputAddActivity activities)
+      throws ManifoldCFException, ServiceInterruption, IOException {
+
+    Logging.connectors.info("Indexing Document " + documentURI);
+    long indexingTime = System.currentTimeMillis();
+    SpecPacker sp = new SpecPacker(pipelineDescription.getSpecification());
+    Map<String, List<String>> args = sp.getArgs();
+    // Establish a session
+    getSession();
+
+    SearchBloxDocument sbDoc = new SearchBloxDocument(this.apiKey,
+        documentURI, document, args);
+    String format = this.getConfiguration().getParameter(SEARCHBLOX_INDEXING_FORMAT);
+    long startTime = System.currentTimeMillis();
+    try {
+      ResponseCode code = client.addUpdateDocument(sbDoc, format);
+      if (code == ResponseCode.DOCUMENT_INDEXED) {
                 Logging.connectors.info("Document Indexed" + documentURI);
-				activities.recordActivity(startTime, INGEST_ACTIVITY, null,
-						documentURI, "OK", "Document Indexed");}
-			else
-				activities.recordActivity(startTime, INGEST_ACTIVITY, null,
-						documentURI, "" + code.getCode(), code.name());
-		} catch (SearchBloxException e) {
-			Logging.connectors
-					.error("[Indexing - Add] Exception indexing document :"
-							+ document, e);
-			String activityCode = e.getClass().getSimpleName()
-					.toUpperCase(Locale.ROOT);
-			String activityDetails = e.getMessage()
-					+ ((e.getCause() != null) ? ": "
-							+ e.getCause().getMessage() : "");
-			activities.recordActivity(startTime, INGEST_ACTIVITY, null,
-					documentURI, activityCode, activityDetails);
-			return DOCUMENTSTATUS_REJECTED;
-		}
-		indexingTime = System.currentTimeMillis() - indexingTime;
-		Logging.connectors.info("Indexing Time for document " + documentURI + ": " + indexingTime);
-		return DOCUMENTSTATUS_ACCEPTED;
-	}
-
-	/**
-	 * Remove a document using the connector. Note that the last
-	 * outputDescription is included, since it may be necessary for the
-	 * connector to use such information to know how to properly remove the
-	 * document.
-	 *
-	 * @param documentURI
-	 *            is the URI of the document. The URI is presumed to be the
-	 *            unique identifier which the output data store will use to
-	 *            process and serve the document. This URI is constructed by the
-	 *            repository connector which fetches the document, and is thus
-	 *            universal across all output connectors.
-	 * @param outputDescription
-	 *            is the last description string that was constructed for this
-	 *            document by the getOutputDescription() method above.
-	 * @param activities
-	 *            is the handle to an object that the implementer of an output
-	 *            connector may use to perform operations, such as logging
-	 *            processing activity.
-	 */
-	@Override
-	public void removeDocument(String documentURI, String outputDescription,
-			IOutputRemoveActivity activities) throws ManifoldCFException,
-			ServiceInterruption {
-		Logging.ingest.debug("Deleting SearchBlox Document: '" + documentURI
-				+ "'");
-
-		SpecPacker packer = new SpecPacker(outputDescription);
-		Map<String, List<String>> args = packer.getArgs();
-		// Establish a session
-		getSession();
-		
-		SearchBloxDocument document = new SearchBloxDocument(this.apiKey);
-		document.uid = documentURI;
-		// document.apiKey = args.get(API_KEY).get(0);
-		document.colName = args.get(SearchBloxDocument.SEARCHBLOX_COLLECTION).get(0);
-		String format = args.get(SEARCHBLOX_INDEXING_FORMAT).get(0);
-		long startTime = System.currentTimeMillis();
-		try {
-			ResponseCode code = client.deleteDocument(document, format);
-			if (code == ResponseCode.DOCUMENT_DELETED)
-				activities.recordActivity(startTime, REMOVE_ACTIVITY, null,
-						documentURI, "OK", "Document Deleted");
-			else
-				activities.recordActivity(startTime, REMOVE_ACTIVITY, null,
-						documentURI, "" + code.getCode(), code.name());
-		} catch (SearchBloxException e) {
-			Logging.connectors.error(
-					"[Indexing - Remove] Exception indexing document :"
-							+ document, e);
-			String activityCode = e.getClass().getSimpleName()
-					.toUpperCase(Locale.ROOT);
-			String activityDetails = e.getMessage()
-					+ ((e.getCause() != null) ? ": "
-							+ e.getCause().getMessage() : "");
-			activities.recordActivity(startTime, REMOVE_ACTIVITY, null,
-					documentURI, activityCode, activityDetails);
-		}
-	}
-
-	/**
-	 * Read the content of a resource, replace the variable ${PARAMNAME} with
-	 * the value and copy it to the out.
-	 * 
-	 * @param resName
-	 * @param out
-	 * @throws ManifoldCFException
-	 */
-	private static void outputResource(String resName, IHTTPOutput out,
-			Locale locale, Map<String, String> params, String tabName,
-			Integer sequenceNumber, Integer currentSequenceNumber)
-			throws ManifoldCFException {
-		Map<String, String> paramMap = null;
-		if (params != null) {
-			paramMap = params;
-			if (tabName != null) {
-				paramMap.put("TabName", tabName);
-			}
-			if (currentSequenceNumber != null)
-				paramMap.put("SelectedNum", currentSequenceNumber.toString());
-		} else {
-			paramMap = new HashMap<String, String>();
-		}
-		if (sequenceNumber != null)
-			paramMap.put("SeqNum", sequenceNumber.toString());
-
-		Messages.outputResourceWithVelocity(out, locale, resName, paramMap,
-				true);
-	}
-
-	@Override
-	public void outputConfigurationHeader(IThreadContext threadContext,
-			IHTTPOutput out, Locale locale, ConfigParams parameters,
-			List<String> tabsArray) throws ManifoldCFException, IOException {
-		super.outputConfigurationHeader(threadContext, out, locale, parameters,
-				tabsArray);
-		tabsArray.add(Messages.getString(locale, SEARCHBLOX_TAB_PARAMETERS));
-		outputResource(EDIT_CONFIG_HEADER_FORWARD, out, locale, null, null,
-				null, null);
-	}
-
-	@Override
-	public void outputConfigurationBody(IThreadContext threadContext,
-			IHTTPOutput out, Locale locale, ConfigParams parameters,
-			String tabName) throws ManifoldCFException, IOException {
-		super.outputConfigurationBody(threadContext, out, locale, parameters,
-				tabName);
-		Map<String, String> config = getConfigParameters(parameters);
-		outputResource(EDIT_CONFIG_FORWARD_PARAMETERS, out, locale, config,
-				tabName, null, null);
-	}
-
-	/**
-	 * Build a Map of SearchBlox parameters. If configParams is null,
-	 * getConfiguration() is used.
-	 * 
-	 * @param configParams
-	 */
-	final private Map<String, String> getConfigParameters(
-			ConfigParams configParams) {
-		Map<String, String> map = new HashMap<String, String>();
-
-		String apiKey = configParams.getParameter(SearchBloxDocument.API_KEY);
-		if(apiKey == null)
-			apiKey = DEFAULT_APIKEY;
-		map.put(SearchBloxDocument.API_KEY, apiKey);
-		
-		String endpoint = configParams.getParameter(SEARCHBLOX_ENDPOINT);
-		if(endpoint == null) {
-			endpoint = SearchBloxClient.DEFAULT_ENDPOINT;
-		}
-		map.put(SEARCHBLOX_ENDPOINT,
-				endpoint);
-		
-		String indexFormat = configParams.getParameter(SEARCHBLOX_INDEXING_FORMAT);
-		if (indexFormat == null) {
-			indexFormat = IndexingFormat.JSON.name();
-		}
-		map.put(SEARCHBLOX_INDEXING_FORMAT, indexFormat);
-		
-		String connectionTimeout = configParams.getParameter(SEARCHBLOX_CONNECTION_TIMEOUT);
-		if (connectionTimeout == null) {
-			connectionTimeout = BUILDER_DEFAULT_CONNECTION_TIMEOUT;
-		}
-		map.put(SEARCHBLOX_CONNECTION_TIMEOUT, connectionTimeout);
-		
-		String socketTimeout = configParams.getParameter(SEARCHBLOX_SOCKET_TIMEOUT);
-		if (socketTimeout == null) {
-			socketTimeout = BUILDER_DEFAULT_SOCKET_TIMEOUT;
-		}
-		map.put(SEARCHBLOX_SOCKET_TIMEOUT, socketTimeout);
-		
-		return map;
-	}
-
-	@Override
-	public void viewConfiguration(IThreadContext threadContext,
-			IHTTPOutput out, Locale locale, ConfigParams parameters)
-			throws ManifoldCFException, IOException {
-		outputResource(VIEW_CONFIG_FORWARD, out, locale,
-				getConfigParameters(parameters), null, null, null);
-	}
-
-	/**
-	 * Process a configuration post. This method is called at the start of the
-	 * connector's configuration page, whenever there is a possibility that form
-	 * data for a connection has been posted. Its purpose is to gather form
-	 * information and modify the configuration parameters accordingly. The name
-	 * of the posted form is "editconnection".
-	 *
-	 * @param threadContext
-	 *            is the local thread context.
-	 * @param variableContext
-	 *            is the set of variables available from the post, including
-	 *            binary file post information.
-	 * @param parameters
-	 *            are the configuration parameters, as they currently exist, for
-	 *            this connection being configured.
-	 * @return null if all is well, or a string error message if there is an
-	 *         error that should prevent saving of the connection (and cause a
-	 *         redirection to an error page).
-	 */
-	@Override
-	public String processConfigurationPost(IThreadContext threadContext,
-			IPostParameters variableContext, Locale locale,
-			ConfigParams parameters) throws ManifoldCFException {
-		String apiKey = variableContext.getParameter(SearchBloxDocument.API_KEY);
-		if (apiKey != null)
-			parameters.setParameter(SearchBloxDocument.API_KEY, apiKey);
-
-		String endpoint = variableContext.getParameter(SEARCHBLOX_ENDPOINT);
-		if (endpoint != null)
-			parameters.setParameter(SEARCHBLOX_ENDPOINT, endpoint);
-		
-		String indexformat = variableContext.getParameter(SEARCHBLOX_INDEXING_FORMAT);
-		if (indexformat != null)
-			parameters.setParameter(SEARCHBLOX_INDEXING_FORMAT, indexformat);
-
-		String connectionTimeout = variableContext.getParameter(SEARCHBLOX_CONNECTION_TIMEOUT);
-		if (connectionTimeout != null)
-			parameters.setParameter(SEARCHBLOX_CONNECTION_TIMEOUT, connectionTimeout);
-		
-		String socketTimeout = variableContext.getParameter(SEARCHBLOX_SOCKET_TIMEOUT);
-		if (socketTimeout != null)
-			parameters.setParameter(SEARCHBLOX_SOCKET_TIMEOUT, socketTimeout);
-		
-		return null;
-	}
-
-	/**
-	 * Output the specification header section. This method is called in the
-	 * head section of a job page which has selected a pipeline connection of
-	 * the current type. Its purpose is to add the required tabs to the list,
-	 * and to output any javascript methods that might be needed by the job
-	 * editing HTML.
-	 *
-	 * @param out
-	 *            is the output to which any HTML should be sent.
-	 * @param locale
-	 *            is the preferred local of the output.
-	 * @param os
-	 *            is the current pipeline specification for this connection.
-	 * @param connectionSequenceNumber
-	 *            is the unique number of this connection within the job.
-	 * @param tabsArray
-	 *            is an array of tab names. Add to this array any tab names that
-	 *            are specific to the connector.
-	 */
-	@Override
-	public void outputSpecificationHeader(IHTTPOutput out, Locale locale,
-			Specification os, int connectionSequenceNumber,
-			List<String> tabsArray) throws ManifoldCFException, IOException {
-		Map<String, Object> paramMap = new HashMap<String, Object>();
-		paramMap.put("SEQNUM", Integer.toString(connectionSequenceNumber));
-
-		tabsArray.add(Messages.getString(locale,
-				"SearchBloxConnector.Configuration"));
-
-		// Fill in the specification header map, using data from all tabs.
-		fillInSpecificationMap(paramMap, os);
-
-		Messages.outputResourceWithVelocity(out, locale, EDIT_SPECIFICATION_JS,
-				paramMap);
-	}
-
-	private void fillInSpecificationMap(
-			Map<String, Object> paramMap, Specification os) {
-
-		for (int i = 0, len = os.getChildCount(); i < len; i++) {
-			SpecificationNode sn = os.getChild(i);
-			if (sn.getType().equals(SearchBloxConfig.NODE_CONFIGURATION)) {
-
-				String titleBoost = sn
-						.getAttributeValue(SearchBloxConfig.ATTRIBUTE_TITLEBOOST);
-				if (titleBoost == null || titleBoost.isEmpty())
-					titleBoost = "0";
-				String contentBoost = sn
-						.getAttributeValue(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST);
-				if (contentBoost == null || contentBoost.isEmpty())
-					contentBoost = "0";
-				String keywordsBoost = sn
-						.getAttributeValue(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST);
-				if (keywordsBoost == null || keywordsBoost.isEmpty())
-					keywordsBoost = "0";
-				String descriptionBoost = sn
-						.getAttributeValue(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST);
-				if (descriptionBoost == null || descriptionBoost.isEmpty())
-					descriptionBoost = "0";
-
-				String collection = sn
-						.getAttributeValue(SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME);
-				if (collection == null)
-					collection = DEFAULT_COLLECTION;
-				
-				paramMap.put(SearchBloxConfig.ATTRIBUTE_TITLEBOOST.toUpperCase(),
-						titleBoost);
-				paramMap.put(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST.toUpperCase(),
-						contentBoost);
-				paramMap.put(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST.toUpperCase(),
-						keywordsBoost);
-				paramMap.put(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST.toUpperCase(),
-						descriptionBoost);
-				paramMap.put(SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME
-						.toUpperCase(), collection);
-
-				return;
-			}
-
-		}
-
-		paramMap.put(SearchBloxConfig.ATTRIBUTE_TITLEBOOST.toUpperCase(), 0);
-		paramMap.put(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST.toUpperCase(), 0);
-		paramMap.put(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST.toUpperCase(), 0);
-		paramMap.put(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST.toUpperCase(), 0);
-		paramMap.put(SearchBloxConfig.ATTRIBUTE_INDEX_FORMAT.toUpperCase(),
-				IndexingFormat.XML.name());
-		paramMap.put(SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME.toUpperCase(),
-				"");
-
-	}
-
-	/**
-	 * View specification. This method is called in the body section of a job's
-	 * view page. Its purpose is to present the pipeline specification
-	 * information to the user. The coder can presume that the HTML that is
-	 * output from this configuration will be within appropriate <html> and
-	 * <body> tags.
-	 *
-	 * @param out
-	 *            is the output to which any HTML should be sent.
-	 * @param locale
-	 *            is the preferred local of the output.
-	 * @param connectionSequenceNumber
-	 *            is the unique number of this connection within the job.
-	 * @param os
-	 *            is the current pipeline specification for this job.
-	 */
-	@Override
-	public void viewSpecification(IHTTPOutput out, Locale locale,
-			Specification os, int connectionSequenceNumber)
-			throws ManifoldCFException, IOException {
-		Map<String, Object> paramMap = new HashMap<String, Object>();
-		paramMap.put("SEQNUM", Integer.toString(connectionSequenceNumber));
-
-		// Fill in the map with data from all tabs
-		fillInSpecificationMap(paramMap, os);
-
-		Messages.outputResourceWithVelocity(out, locale,
-				VIEW_SPECIFICATION_HTML, paramMap);
-
-	}
-
-	/**
-	 * Output the specification body section. This method is called in the body
-	 * section of a job page which has selected a pipeline connection of the
-	 * current type. Its purpose is to present the required form elements for
-	 * editing. The coder can presume that the HTML that is output from this
-	 * configuration will be within appropriate <html>, <body>, and <form> tags.
-	 * The name of the form is "editjob".
-	 *
-	 * @param out
-	 *            is the output to which any HTML should be sent.
-	 * @param locale
-	 *            is the preferred local of the output.
-	 * @param os
-	 *            is the current pipeline specification for this job.
-	 * @param connectionSequenceNumber
-	 *            is the unique number of this connection within the job.
-	 * @param actualSequenceNumber
-	 *            is the connection within the job that has currently been
-	 *            selected.
-	 * @param tabName
-	 *            is the current tab name.
-	 */
-	@Override
-	public void outputSpecificationBody(IHTTPOutput out, Locale locale,
-			Specification os, int connectionSequenceNumber,
-			int actualSequenceNumber, String tabName)
-			throws ManifoldCFException, IOException {
-		Map<String, Object> paramMap = new HashMap<String, Object>();
-
-		// Set the tab name
-		paramMap.put("TABNAME", tabName);
-		paramMap.put("SEQNUM", Integer.toString(connectionSequenceNumber));
-		paramMap.put("SELECTEDNUM", Integer.toString(actualSequenceNumber));
-
-		// Fill in the field mapping tab data
-		fillInSpecificationMap(paramMap, os);
-
-		Messages.outputResourceWithVelocity(out, locale,
-				EDIT_SPECIFICATION_CONFIGURATION_HTML, paramMap);
-
-	}
-
-	/**
-	 * Process a specification post. This method is called at the start of job's
-	 * edit or view page, whenever there is a possibility that form data for a
-	 * connection has been posted. Its purpose is to gather form information and
-	 * modify the transformation specification accordingly. The name of the
-	 * posted form is "editjob".
-	 *
-	 * @param variableContext
-	 *            contains the post data, including binary file-upload
-	 *            information.
-	 * @param locale
-	 *            is the preferred local of the output.
-	 * @param os
-	 *            is the current pipeline specification for this job.
-	 * @param connectionSequenceNumber
-	 *            is the unique number of this connection within the job.
-	 * @return null if all is well, or a string error message if there is an
-	 *         error that should prevent saving of the job (and cause a
-	 *         redirection to an error page).
-	 */
-	@Override
-	public String processSpecificationPost(IPostParameters variableContext,
-			Locale locale, Specification os, int connectionSequenceNumber)
-			throws ManifoldCFException {
-		String seqPrefix = "s" + connectionSequenceNumber + "_";
-		String titleBoost = variableContext.getParameter(seqPrefix
-				+ SearchBloxConfig.ATTRIBUTE_TITLEBOOST);
-		String contentBoost = variableContext.getParameter(seqPrefix
-				+ SearchBloxConfig.ATTRIBUTE_CONTENTBOOST);
-		String keywordsBoost = variableContext.getParameter(seqPrefix
-				+ SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST);
-		String descriptionBoost = variableContext.getParameter(seqPrefix
-				+ SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST);
-		String collection = variableContext.getParameter(seqPrefix
-				+ SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME);
-		String indexFormat = variableContext.getParameter(seqPrefix
-				+ SearchBloxConfig.ATTRIBUTE_INDEX_FORMAT);
-
-		// About to gather the configuration values, so get rid of the old one.
-		int i = 0, len = os.getChildCount();
-		while (i < len) {
-			SpecificationNode node = os.getChild(i);
-			if (node.getType().equals(SearchBloxConfig.NODE_CONFIGURATION))
-				os.removeChild(i);
-			else
-				i++;
-		}
-
-		SpecificationNode node = new SpecificationNode(
-				SearchBloxConfig.NODE_CONFIGURATION);
-		node.setAttribute(SearchBloxConfig.ATTRIBUTE_TITLEBOOST, titleBoost);
-		node.setAttribute(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST, contentBoost);
-		node.setAttribute(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST, keywordsBoost);
-		node.setAttribute(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST, descriptionBoost);
-		node.setAttribute(SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME,
-				collection);
-		node.setAttribute(SearchBloxConfig.ATTRIBUTE_INDEX_FORMAT, indexFormat);
-		os.addChild(os.getChildCount(), node);
-
-		return null;
-
-	}
-	
-
-	protected static class SpecPacker {
-		/** Arguments, from configuration */
-	    private final Multimap<String, String> args = HashMultimap.create();
-	    
-	    public SpecPacker(String outputDescription) {
-	    	String[] parts = outputDescription.split(",");
-	    	for(String part : parts) {
-	    		String[] keyValue = part.split("=");
-	    		if(keyValue.length != 2) {
-	    			continue;
-	    		}
-	    		
-	    		args.put(keyValue[0], keyValue[1]);
-	    	}
-	    }
-	    
-	    public SpecPacker(Specification spec) {
-	      // Process arguments
-	      for (int i = 0; i < spec.getChildCount(); i++)
-	      {
-              SpecificationNode node = spec.getChild(i);
-              if (node.getType().equals(SearchBloxConfig.NODE_CONFIGURATION))
-	        {
-	          String titleBoost = node.getAttributeValue(SearchBloxConfig.ATTRIBUTE_TITLEBOOST);
-	          String contentBoost = node.getAttributeValue(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST);
-	          String keywordsBoost = node.getAttributeValue(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST);
-	          String descriptionBoost = node.getAttributeValue(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST);
-	          String collection = node.getAttributeValue(SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME);
-	          args.put(SearchBloxConfig.ATTRIBUTE_TITLEBOOST, titleBoost);
-	          args.put(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST, contentBoost);
-	          args.put(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST, keywordsBoost);
-	          args.put(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST, descriptionBoost);
-	          args.put(SearchBloxDocument.SEARCHBLOX_COLLECTION, collection);
-	          
-	        }
-	      }
-	    
-	    }
-	    
-	    public String toPackedString() {
-	    	Map<String, List<String>> mapList = getArgs();
-	    	StringBuilder sb = new StringBuilder();
-	    	for(String s : mapList.keySet()) {
-	    		sb.append(s).append("=").append(mapList.get(s).get(0));
-	    		sb.append(",");
-	    	}
-	    	if(sb.toString().length()!=0)
-	    	    return sb.substring(0, sb.length()-1);
-            else
-                return "";
-	    	
-	    }
-	    
-	    public Map<String,List<String>> getArgs() {
-	    	Map<String,List<String>> result = Maps.newHashMap();
-	    	for(String s : args.keySet()) {
-	    		Collection<String> list = args.get(s);
-	    		if(list instanceof List) {
-	    			result.put(s,  (List<String>) list);
-	    		}
-	    		else {
-	    			List<String> l = Lists.newArrayList(list);
-	    			result.put(s,  l);
-	    		}
-	    	}
-	      return result;
-	    }
-	}
+        activities.recordActivity(startTime, INGEST_ACTIVITY, null,
+            documentURI, "OK", "Document Indexed");}
+      else
+        activities.recordActivity(startTime, INGEST_ACTIVITY, null,
+            documentURI, "" + code.getCode(), code.name());
+    } catch (SearchBloxException e) {
+      Logging.connectors
+          .error("[Indexing - Add] Exception indexing document :"
+              + document, e);
+      String activityCode = e.getClass().getSimpleName()
+          .toUpperCase(Locale.ROOT);
+      String activityDetails = e.getMessage()
+          + ((e.getCause() != null) ? ": "
+              + e.getCause().getMessage() : "");
+      activities.recordActivity(startTime, INGEST_ACTIVITY, null,
+          documentURI, activityCode, activityDetails);
+      return DOCUMENTSTATUS_REJECTED;
+    }
+    indexingTime = System.currentTimeMillis() - indexingTime;
+    Logging.connectors.info("Indexing Time for document " + documentURI + ": " + indexingTime);
+    return DOCUMENTSTATUS_ACCEPTED;
+  }
+
+  /**
+   * Remove a document using the connector. Note that the last
+   * outputDescription is included, since it may be necessary for the
+   * connector to use such information to know how to properly remove the
+   * document.
+   *
+   * @param documentURI
+   *            is the URI of the document. The URI is presumed to be the
+   *            unique identifier which the output data store will use to
+   *            process and serve the document. This URI is constructed by the
+   *            repository connector which fetches the document, and is thus
+   *            universal across all output connectors.
+   * @param outputDescription
+   *            is the last description string that was constructed for this
+   *            document by the getOutputDescription() method above.
+   * @param activities
+   *            is the handle to an object that the implementer of an output
+   *            connector may use to perform operations, such as logging
+   *            processing activity.
+   */
+  @Override
+  public void removeDocument(String documentURI, String outputDescription,
+      IOutputRemoveActivity activities) throws ManifoldCFException,
+      ServiceInterruption {
+    Logging.ingest.debug("Deleting SearchBlox Document: '" + documentURI
+        + "'");
+
+    SpecPacker packer = new SpecPacker(outputDescription);
+    Map<String, List<String>> args = packer.getArgs();
+    // Establish a session
+    getSession();
+    
+    SearchBloxDocument document = new SearchBloxDocument(this.apiKey);
+    document.uid = documentURI;
+    // document.apiKey = args.get(API_KEY).get(0);
+    document.colName = args.get(SearchBloxDocument.SEARCHBLOX_COLLECTION).get(0);
+    String format = args.get(SEARCHBLOX_INDEXING_FORMAT).get(0);
+    long startTime = System.currentTimeMillis();
+    try {
+      ResponseCode code = client.deleteDocument(document, format);
+      if (code == ResponseCode.DOCUMENT_DELETED)
+        activities.recordActivity(startTime, REMOVE_ACTIVITY, null,
+            documentURI, "OK", "Document Deleted");
+      else
+        activities.recordActivity(startTime, REMOVE_ACTIVITY, null,
+            documentURI, "" + code.getCode(), code.name());
+    } catch (SearchBloxException e) {
+      Logging.connectors.error(
+          "[Indexing - Remove] Exception indexing document :"
+              + document, e);
+      String activityCode = e.getClass().getSimpleName()
+          .toUpperCase(Locale.ROOT);
+      String activityDetails = e.getMessage()
+          + ((e.getCause() != null) ? ": "
+              + e.getCause().getMessage() : "");
+      activities.recordActivity(startTime, REMOVE_ACTIVITY, null,
+          documentURI, activityCode, activityDetails);
+    }
+  }
+
+  /**
+   * Read the content of a resource, replace the variable ${PARAMNAME} with
+   * the value and copy it to the out.
+   * 
+   * @param resName
+   * @param out
+   * @throws ManifoldCFException
+   */
+  private static void outputResource(String resName, IHTTPOutput out,
+      Locale locale, Map<String, String> params, String tabName,
+      Integer sequenceNumber, Integer currentSequenceNumber)
+      throws ManifoldCFException {
+    Map<String, String> paramMap = null;
+    if (params != null) {
+      paramMap = params;
+      if (tabName != null) {
+        paramMap.put("TabName", tabName);
+      }
+      if (currentSequenceNumber != null)
+        paramMap.put("SelectedNum", currentSequenceNumber.toString());
+    } else {
+      paramMap = new HashMap<String, String>();
+    }
+    if (sequenceNumber != null)
+      paramMap.put("SeqNum", sequenceNumber.toString());
+
+    Messages.outputResourceWithVelocity(out, locale, resName, paramMap,
+        true);
+  }
+
+  @Override
+  public void outputConfigurationHeader(IThreadContext threadContext,
+      IHTTPOutput out, Locale locale, ConfigParams parameters,
+      List<String> tabsArray) throws ManifoldCFException, IOException {
+    super.outputConfigurationHeader(threadContext, out, locale, parameters,
+        tabsArray);
+    tabsArray.add(Messages.getString(locale, SEARCHBLOX_TAB_PARAMETERS));
+    outputResource(EDIT_CONFIG_HEADER_FORWARD, out, locale, null, null,
+        null, null);
+  }
+
+  @Override
+  public void outputConfigurationBody(IThreadContext threadContext,
+      IHTTPOutput out, Locale locale, ConfigParams parameters,
+      String tabName) throws ManifoldCFException, IOException {
+    super.outputConfigurationBody(threadContext, out, locale, parameters,
+        tabName);
+    Map<String, String> config = getConfigParameters(parameters);
+    outputResource(EDIT_CONFIG_FORWARD_PARAMETERS, out, locale, config,
+        tabName, null, null);
+  }
+
+  /**
+   * Build a Map of SearchBlox parameters. If configParams is null,
+   * getConfiguration() is used.
+   * 
+   * @param configParams
+   */
+  final private Map<String, String> getConfigParameters(
+      ConfigParams configParams) {
+    Map<String, String> map = new HashMap<String, String>();
+
+    String apiKey = configParams.getParameter(SearchBloxDocument.API_KEY);
+    if(apiKey == null)
+      apiKey = DEFAULT_APIKEY;
+    map.put(SearchBloxDocument.API_KEY, apiKey);
+    
+    String endpoint = configParams.getParameter(SEARCHBLOX_ENDPOINT);
+    if(endpoint == null) {
+      endpoint = SearchBloxClient.DEFAULT_ENDPOINT;
+    }
+    map.put(SEARCHBLOX_ENDPOINT,
+        endpoint);
+    
+    String indexFormat = configParams.getParameter(SEARCHBLOX_INDEXING_FORMAT);
+    if (indexFormat == null) {
+      indexFormat = IndexingFormat.JSON.name();
+    }
+    map.put(SEARCHBLOX_INDEXING_FORMAT, indexFormat);
+    
+    String connectionTimeout = configParams.getParameter(SEARCHBLOX_CONNECTION_TIMEOUT);
+    if (connectionTimeout == null) {
+      connectionTimeout = BUILDER_DEFAULT_CONNECTION_TIMEOUT;
+    }
+    map.put(SEARCHBLOX_CONNECTION_TIMEOUT, connectionTimeout);
+    
+    String socketTimeout = configParams.getParameter(SEARCHBLOX_SOCKET_TIMEOUT);
+    if (socketTimeout == null) {
+      socketTimeout = BUILDER_DEFAULT_SOCKET_TIMEOUT;
+    }
+    map.put(SEARCHBLOX_SOCKET_TIMEOUT, socketTimeout);
+    
+    return map;
+  }
+
+  @Override
+  public void viewConfiguration(IThreadContext threadContext,
+      IHTTPOutput out, Locale locale, ConfigParams parameters)
+      throws ManifoldCFException, IOException {
+    outputResource(VIEW_CONFIG_FORWARD, out, locale,
+        getConfigParameters(parameters), null, null, null);
+  }
+
+  /**
+   * Process a configuration post. This method is called at the start of the
+   * connector's configuration page, whenever there is a possibility that form
+   * data for a connection has been posted. Its purpose is to gather form
+   * information and modify the configuration parameters accordingly. The name
+   * of the posted form is "editconnection".
+   *
+   * @param threadContext
+   *            is the local thread context.
+   * @param variableContext
+   *            is the set of variables available from the post, including
+   *            binary file post information.
+   * @param parameters
+   *            are the configuration parameters, as they currently exist, for
+   *            this connection being configured.
+   * @return null if all is well, or a string error message if there is an
+   *         error that should prevent saving of the connection (and cause a
+   *         redirection to an error page).
+   */
+  @Override
+  public String processConfigurationPost(IThreadContext threadContext,
+      IPostParameters variableContext, Locale locale,
+      ConfigParams parameters) throws ManifoldCFException {
+    String apiKey = variableContext.getParameter(SearchBloxDocument.API_KEY);
+    if (apiKey != null)
+      parameters.setParameter(SearchBloxDocument.API_KEY, apiKey);
+
+    String endpoint = variableContext.getParameter(SEARCHBLOX_ENDPOINT);
+    if (endpoint != null)
+      parameters.setParameter(SEARCHBLOX_ENDPOINT, endpoint);
+    
+    String indexformat = variableContext.getParameter(SEARCHBLOX_INDEXING_FORMAT);
+    if (indexformat != null)
+      parameters.setParameter(SEARCHBLOX_INDEXING_FORMAT, indexformat);
+
+    String connectionTimeout = variableContext.getParameter(SEARCHBLOX_CONNECTION_TIMEOUT);
+    if (connectionTimeout != null)
+      parameters.setParameter(SEARCHBLOX_CONNECTION_TIMEOUT, connectionTimeout);
+    
+    String socketTimeout = variableContext.getParameter(SEARCHBLOX_SOCKET_TIMEOUT);
+    if (socketTimeout != null)
+      parameters.setParameter(SEARCHBLOX_SOCKET_TIMEOUT, socketTimeout);
+    
+    return null;
+  }
+
+  /**
+   * Output the specification header section. This method is called in the
+   * head section of a job page which has selected a pipeline connection of
+   * the current type. Its purpose is to add the required tabs to the list,
+   * and to output any javascript methods that might be needed by the job
+   * editing HTML.
+   *
+   * @param out
+   *            is the output to which any HTML should be sent.
+   * @param locale
+   *            is the preferred local of the output.
+   * @param os
+   *            is the current pipeline specification for this connection.
+   * @param connectionSequenceNumber
+   *            is the unique number of this connection within the job.
+   * @param tabsArray
+   *            is an array of tab names. Add to this array any tab names that
+   *            are specific to the connector.
+   */
+  @Override
+  public void outputSpecificationHeader(IHTTPOutput out, Locale locale,
+      Specification os, int connectionSequenceNumber,
+      List<String> tabsArray) throws ManifoldCFException, IOException {
+    Map<String, Object> paramMap = new HashMap<String, Object>();
+    paramMap.put("SEQNUM", Integer.toString(connectionSequenceNumber));
+
+    tabsArray.add(Messages.getString(locale,
+        "SearchBloxConnector.Configuration"));
+
+    // Fill in the specification header map, using data from all tabs.
+    fillInSpecificationMap(paramMap, os);
+
+    Messages.outputResourceWithVelocity(out, locale, EDIT_SPECIFICATION_JS,
+        paramMap);
+  }
+
+  private void fillInSpecificationMap(
+      Map<String, Object> paramMap, Specification os) {
+
+    for (int i = 0, len = os.getChildCount(); i < len; i++) {
+      SpecificationNode sn = os.getChild(i);
+      if (sn.getType().equals(SearchBloxConfig.NODE_CONFIGURATION)) {
+
+        String titleBoost = sn
+            .getAttributeValue(SearchBloxConfig.ATTRIBUTE_TITLEBOOST);
+        if (titleBoost == null || titleBoost.isEmpty())
+          titleBoost = "0";
+        String contentBoost = sn
+            .getAttributeValue(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST);
+        if (contentBoost == null || contentBoost.isEmpty())
+          contentBoost = "0";
+        String keywordsBoost = sn
+            .getAttributeValue(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST);
+        if (keywordsBoost == null || keywordsBoost.isEmpty())
+          keywordsBoost = "0";
+        String descriptionBoost = sn
+            .getAttributeValue(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST);
+        if (descriptionBoost == null || descriptionBoost.isEmpty())
+          descriptionBoost = "0";
+
+        String collection = sn
+            .getAttributeValue(SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME);
+        if (collection == null)
+          collection = DEFAULT_COLLECTION;
+        
+        paramMap.put(SearchBloxConfig.ATTRIBUTE_TITLEBOOST.toUpperCase(),
+            titleBoost);
+        paramMap.put(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST.toUpperCase(),
+            contentBoost);
+        paramMap.put(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST.toUpperCase(),
+            keywordsBoost);
+        paramMap.put(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST.toUpperCase(),
+            descriptionBoost);
+        paramMap.put(SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME
+            .toUpperCase(), collection);
+
+        return;
+      }
+
+    }
+
+    paramMap.put(SearchBloxConfig.ATTRIBUTE_TITLEBOOST.toUpperCase(), 0);
+    paramMap.put(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST.toUpperCase(), 0);
+    paramMap.put(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST.toUpperCase(), 0);
+    paramMap.put(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST.toUpperCase(), 0);
+    paramMap.put(SearchBloxConfig.ATTRIBUTE_INDEX_FORMAT.toUpperCase(),
+        IndexingFormat.XML.name());
+    paramMap.put(SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME.toUpperCase(),
+        "");
+
+  }
+
+  /**
+   * View specification. This method is called in the body section of a job's
+   * view page. Its purpose is to present the pipeline specification
+   * information to the user. The coder can presume that the HTML that is
+   * output from this configuration will be within appropriate <html> and
+   * <body> tags.
+   *
+   * @param out
+   *            is the output to which any HTML should be sent.
+   * @param locale
+   *            is the preferred local of the output.
+   * @param connectionSequenceNumber
+   *            is the unique number of this connection within the job.
+   * @param os
+   *            is the current pipeline specification for this job.
+   */
+  @Override
+  public void viewSpecification(IHTTPOutput out, Locale locale,
+      Specification os, int connectionSequenceNumber)
+      throws ManifoldCFException, IOException {
+    Map<String, Object> paramMap = new HashMap<String, Object>();
+    paramMap.put("SEQNUM", Integer.toString(connectionSequenceNumber));
+
+    // Fill in the map with data from all tabs
+    fillInSpecificationMap(paramMap, os);
+
+    Messages.outputResourceWithVelocity(out, locale,
+        VIEW_SPECIFICATION_HTML, paramMap);
+
+  }
+
+  /**
+   * Output the specification body section. This method is called in the body
+   * section of a job page which has selected a pipeline connection of the
+   * current type. Its purpose is to present the required form elements for
+   * editing. The coder can presume that the HTML that is output from this
+   * configuration will be within appropriate <html>, <body>, and <form> tags.
+   * The name of the form is "editjob".
+   *
+   * @param out
+   *            is the output to which any HTML should be sent.
+   * @param locale
+   *            is the preferred local of the output.
+   * @param os
+   *            is the current pipeline specification for this job.
+   * @param connectionSequenceNumber
+   *            is the unique number of this connection within the job.
+   * @param actualSequenceNumber
+   *            is the connection within the job that has currently been
+   *            selected.
+   * @param tabName
+   *            is the current tab name.
+   */
+  @Override
+  public void outputSpecificationBody(IHTTPOutput out, Locale locale,
+      Specification os, int connectionSequenceNumber,
+      int actualSequenceNumber, String tabName)
+      throws ManifoldCFException, IOException {
+    Map<String, Object> paramMap = new HashMap<String, Object>();
+
+    // Set the tab name
+    paramMap.put("TABNAME", tabName);
+    paramMap.put("SEQNUM", Integer.toString(connectionSequenceNumber));
+    paramMap.put("SELECTEDNUM", Integer.toString(actualSequenceNumber));
+
+    // Fill in the field mapping tab data
+    fillInSpecificationMap(paramMap, os);
+
+    Messages.outputResourceWithVelocity(out, locale,
+        EDIT_SPECIFICATION_CONFIGURATION_HTML, paramMap);
+
+  }
+
+  /**
+   * Process a specification post. This method is called at the start of job's
+   * edit or view page, whenever there is a possibility that form data for a
+   * connection has been posted. Its purpose is to gather form information and
+   * modify the transformation specification accordingly. The name of the
+   * posted form is "editjob".
+   *
+   * @param variableContext
+   *            contains the post data, including binary file-upload
+   *            information.
+   * @param locale
+   *            is the preferred local of the output.
+   * @param os
+   *            is the current pipeline specification for this job.
+   * @param connectionSequenceNumber
+   *            is the unique number of this connection within the job.
+   * @return null if all is well, or a string error message if there is an
+   *         error that should prevent saving of the job (and cause a
+   *         redirection to an error page).
+   */
+  @Override
+  public String processSpecificationPost(IPostParameters variableContext,
+      Locale locale, Specification os, int connectionSequenceNumber)
+      throws ManifoldCFException {
+    String seqPrefix = "s" + connectionSequenceNumber + "_";
+    String titleBoost = variableContext.getParameter(seqPrefix
+        + SearchBloxConfig.ATTRIBUTE_TITLEBOOST);
+    String contentBoost = variableContext.getParameter(seqPrefix
+        + SearchBloxConfig.ATTRIBUTE_CONTENTBOOST);
+    String keywordsBoost = variableContext.getParameter(seqPrefix
+        + SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST);
+    String descriptionBoost = variableContext.getParameter(seqPrefix
+        + SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST);
+    String collection = variableContext.getParameter(seqPrefix
+        + SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME);
+    String indexFormat = variableContext.getParameter(seqPrefix
+        + SearchBloxConfig.ATTRIBUTE_INDEX_FORMAT);
+
+    // About to gather the configuration values, so get rid of the old one.
+    int i = 0, len = os.getChildCount();
+    while (i < len) {
+      SpecificationNode node = os.getChild(i);
+      if (node.getType().equals(SearchBloxConfig.NODE_CONFIGURATION))
+        os.removeChild(i);
+      else
+        i++;
+    }
+
+    SpecificationNode node = new SpecificationNode(
+        SearchBloxConfig.NODE_CONFIGURATION);
+    node.setAttribute(SearchBloxConfig.ATTRIBUTE_TITLEBOOST, titleBoost);
+    node.setAttribute(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST, contentBoost);
+    node.setAttribute(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST, keywordsBoost);
+    node.setAttribute(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST, descriptionBoost);
+    node.setAttribute(SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME,
+        collection);
+    node.setAttribute(SearchBloxConfig.ATTRIBUTE_INDEX_FORMAT, indexFormat);
+    os.addChild(os.getChildCount(), node);
+
+    return null;
+
+  }
+  
+
+  protected static class SpecPacker {
+    /** Arguments, from configuration */
+    private final Multimap<String, String> args = HashMultimap.create();
+      
+    public SpecPacker(String outputDescription) {
+      String[] parts = outputDescription.split(",");
+      for(String part : parts) {
+        String[] keyValue = part.split("=");
+        if(keyValue.length != 2) {
+          continue;
+        }
+          
+        args.put(keyValue[0], keyValue[1]);
+      }
+    }
+      
+    public SpecPacker(Specification spec) {
+      // Process arguments
+      for (int i = 0; i < spec.getChildCount(); i++)
+      {
+        SpecificationNode node = spec.getChild(i);
+        if (node.getType().equals(SearchBloxConfig.NODE_CONFIGURATION))
+        {
+          String titleBoost = node.getAttributeValue(SearchBloxConfig.ATTRIBUTE_TITLEBOOST);
+          String contentBoost = node.getAttributeValue(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST);
+          String keywordsBoost = node.getAttributeValue(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST);
+          String descriptionBoost = node.getAttributeValue(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST);
+          String collection = node.getAttributeValue(SearchBloxConfig.ATTRIBUTE_COLLECTION_NAME);
+          args.put(SearchBloxConfig.ATTRIBUTE_TITLEBOOST, titleBoost);
+          args.put(SearchBloxConfig.ATTRIBUTE_CONTENTBOOST, contentBoost);
+          args.put(SearchBloxConfig.ATTRIBUTE_KEYWORDSBOOST, keywordsBoost);
+          args.put(SearchBloxConfig.ATTRIBUTE_DESCRIPTIONBOOST, descriptionBoost);
+          args.put(SearchBloxDocument.SEARCHBLOX_COLLECTION, collection);
+            
+        }
+      }
+      
+    }
+      
+    public String toPackedString() {
+      Map<String, List<String>> mapList = getArgs();
+      StringBuilder sb = new StringBuilder();
+      for(String s : mapList.keySet()) {
+        sb.append(s).append("=").append(mapList.get(s).get(0));
+        sb.append(",");
+      }
+      if(sb.toString().length()!=0)
+        return sb.substring(0, sb.length()-1);
+      else
+        return "";
+        
+    }
+      
+    public Map<String,List<String>> getArgs() {
+      Map<String,List<String>> result = Maps.newHashMap();
+      for(String s : args.keySet()) {
+        Collection<String> list = args.get(s);
+        if(list instanceof List) {
+          result.put(s,  (List<String>) list);
+        }
+        else {
+          List<String> l = Lists.newArrayList(list);
+          result.put(s,  l);
+        }
+      }
+      return result;
+    }
+  }
 }