Modified: 
manifoldcf/trunk/connectors/confluence/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/confluence/ConfluenceRepositoryConnector.java
URL: 
http://svn.apache.org/viewvc/manifoldcf/trunk/connectors/confluence/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/confluence/ConfluenceRepositoryConnector.java?rev=1707012&r1=1707011&r2=1707012&view=diff
==============================================================================
--- 
manifoldcf/trunk/connectors/confluence/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/confluence/ConfluenceRepositoryConnector.java
 (original)
+++ 
manifoldcf/trunk/connectors/confluence/connector/src/main/java/org/apache/manifoldcf/crawler/connectors/confluence/ConfluenceRepositoryConnector.java
 Tue Oct  6 11:50:34 2015
@@ -52,1202 +52,1202 @@ import com.google.common.collect.Maps;
  */
 public class ConfluenceRepositoryConnector extends BaseRepositoryConnector {
 
-       protected final static String ACTIVITY_READ = "read document";
+  protected final static String ACTIVITY_READ = "read document";
 
-       /** Deny access token for default authority */
-       private final static String defaultAuthorityDenyToken = 
GLOBAL_DENY_TOKEN;
+  /** Deny access token for default authority */
+  private final static String defaultAuthorityDenyToken = GLOBAL_DENY_TOKEN;
 
-       /*
-        * Prefix for Confluence configuration and specification parameters
-        */
-       private static final String PARAMETER_PREFIX = "confluence_";
-
-       /* Configuration tabs */
-       private static final String CONF_SERVER_TAB_PROPERTY = 
"ConfluenceRepositoryConnector.Server";
-
-       /* Specification tabs */
-       private static final String CONF_SPACES_TAB_PROPERTY = 
"ConfluenceRepositoryConnector.Spaces";
-       private static final String CONF_PAGES_TAB_PROPERTY = 
"ConfluenceRepositoryConnector.Pages";
-
-       // pages & js
-       // Template names for Confluence configuration
-       /**
-        * Forward to the javascript to check the configuration parameters
-        */
-       private static final String EDIT_CONFIG_HEADER_FORWARD = 
"editConfiguration_conf.js";
-       /**
-        * Server tab template
-        */
-       private static final String EDIT_CONFIG_FORWARD_SERVER = 
"editConfiguration_conf_server.html";
-
-       /**
-        * Forward to the HTML template to view the configuration parameters
-        */
-       private static final String VIEW_CONFIG_FORWARD = 
"viewConfiguration_conf.html";
-
-       // Template names for Confluence job specification
-       /**
-        * Forward to the javascript to check the specification parameters for 
the
-        * job
-        */
-       private static final String EDIT_SPEC_HEADER_FORWARD = 
"editSpecification_conf.js";
-       /**
-        * Forward to the template to edit the spaces for the job
-        */
-       private static final String EDIT_SPEC_FORWARD_SPACES = 
"editSpecification_confSpaces.html";
-
-       /**
-        * Forward to the template to edit the pages configuration for the job
-        */
-       private static final String EDIT_SPEC_FORWARD_CONF_PAGES = 
"editSpecification_confPages.html";
-
-       /**
-        * Forward to the template to view the specification parameters for the 
job
-        */
-       private static final String VIEW_SPEC_FORWARD = 
"viewSpecification_conf.html";
-
-       protected long lastSessionFetch = -1L;
-       protected static final long timeToRelease = 300000L;
-
-       protected final static long interruptionRetryTime = 5L * 60L * 1000L;
-
-       private Logger logger = LoggerFactory
-                       .getLogger(ConfluenceRepositoryConnector.class);
-
-       /* Confluence instance parameters */
-       protected String protocol = null;
-       protected String host = null;
-       protected String port = null;
-       protected String path = null;
-       protected String username = null;
-       protected String password = null;
-
-       protected ConfluenceClient confluenceClient = null;
-
-       /**
-        * <p>
-        * Default constructor
-        * </p>
-        */
-       public ConfluenceRepositoryConnector() {
-               super();
-       }
-       
-       /**
-        * Set Confluence Client (Mainly for Testing)
-        * 
-        * @param confluenceClient
-        */
-       public void setConfluenceClient(ConfluenceClient confluenceClient){
-               this.confluenceClient = confluenceClient;
-       }
-
-       @Override
-       public String[] getActivitiesList() {
-               return new String[] { ACTIVITY_READ };
-       }
-
-       @Override
-       public String[] getBinNames(String documentIdentifier) {
-               return new String[] { host };
-       }
-
-       /**
-        * Close the connection. Call this before discarding the connection.
-        */
-       @Override
-       public void disconnect() throws ManifoldCFException {
-               if (confluenceClient != null) {
-                       confluenceClient = null;
-               }
-
-               protocol = null;
-               host = null;
-               port = null;
-               path = null;
-               username = null;
-               password = null;
-
-       }
-
-       /**
-        * Makes connection to server
-        * 
-        * 
-        */
-       @Override
-       public void connect(ConfigParams configParams) {
-               super.connect(configParams);
-
-               protocol = 
params.getParameter(ConfluenceConfiguration.Server.PROTOCOL);
-               host = params.getParameter(ConfluenceConfiguration.Server.HOST);
-               port = params.getParameter(ConfluenceConfiguration.Server.PORT);
-               path = params.getParameter(ConfluenceConfiguration.Server.PATH);
-               username = 
params.getParameter(ConfluenceConfiguration.Server.USERNAME);
-               password = params
-                               
.getObfuscatedParameter(ConfluenceConfiguration.Server.PASSWORD);
-
-               try {
-                       initConfluenceClient();
-               } catch (ManifoldCFException e) {
-                       logger.debug(
-                                       "Not possible to initialize Confluence 
client. Reason: {}",
-                                       e.getMessage());
-                       e.printStackTrace();
-               }
-       }
-
-       /**
-        * Checks if connection is available
-        */
-       @Override
-       public String check() throws ManifoldCFException {
-               try {
-                       if (!isConnected()) {
-                               initConfluenceClient();
-                       }
-                       Boolean result = confluenceClient.check();
-                       if (result)
-                               return super.check();
-                       else
-                               throw new ManifoldCFException(
-                                               "Confluence instance could not 
be reached");
-               } catch (ServiceInterruption e) {
-                       return "Connection temporarily failed: " + 
e.getMessage();
-               } catch (ManifoldCFException e) {
-                       return "Connection failed: " + e.getMessage();
-               } catch (Exception e) {
-                       return "Connection failed: " + e.getMessage();
-               }
-       }
-
-       /**
-        * <p>
-        * Initialize Confluence client using the configured parameters
-        * 
-        * @throws ManifoldCFException
-        */
-       protected void initConfluenceClient() throws ManifoldCFException {
-               if (confluenceClient == null) {
-
-                       if (StringUtils.isEmpty(protocol)) {
-                               throw new ManifoldCFException("Parameter "
-                                               + 
ConfluenceConfiguration.Server.PROTOCOL
-                                               + " required but not set");
-                       }
-
-                       if (Logging.connectors.isDebugEnabled()) {
-                               Logging.connectors.debug("Confluence protocol = 
'" + protocol
-                                               + "'");
-                       }
-
-                       if (StringUtils.isEmpty(host)) {
-                               throw new ManifoldCFException("Parameter "
-                                               + 
ConfluenceConfiguration.Server.HOST
-                                               + " required but not set");
-                       }
-
-                       if (Logging.connectors.isDebugEnabled()) {
-                               Logging.connectors.debug("Confluence host = '" 
+ host + "'");
-                       }
-
-                       if (Logging.connectors.isDebugEnabled()) {
-                               Logging.connectors.debug("Confluence port = '" 
+ port + "'");
-                       }
-
-//                     if (StringUtils.isEmpty(path)) {
-//                             throw new ManifoldCFException("Parameter "
-//                                             + 
ConfluenceConfiguration.Server.PATH
-//                                             + " required but not set");
-//                     }
-
-                       if (Logging.connectors.isDebugEnabled()) {
-                               Logging.connectors.debug("Confluence path = '" 
+ path + "'");
-                       }
-
-                       if (Logging.connectors.isDebugEnabled()) {
-                               Logging.connectors.debug("Confluence username = 
'" + username
-                                               + "'");
-                       }
-
-                       if (Logging.connectors.isDebugEnabled()) {
-                               Logging.connectors
-                                               .debug("Confluence password '" 
+ password != null ? "set"
-                                                               : "not set" + 
"'");
-                       }
-
-                       int portInt;
-                       if (port != null && port.length() > 0) {
-                               try {
-                                       portInt = Integer.parseInt(port);
-                               } catch (NumberFormatException e) {
-                                       throw new ManifoldCFException("Bad 
number: "
-                                                       + e.getMessage(), e);
-                               }
-                       } else {
-                               if 
(protocol.toLowerCase(Locale.ROOT).equals("http"))
-                                       portInt = 80;
-                               else
-                                       portInt = 443;
-                       }
-
-                       /* Generating a client to perform Confluence requests */
-                       confluenceClient = new ConfluenceClient(protocol, host, 
portInt,
-                                       path, username, password);
-                       lastSessionFetch = System.currentTimeMillis();
-               }
-
-       }
-
-       /**
-        * 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 confluenceClient != null;
-       }
-
-       @Override
-       public void poll() throws ManifoldCFException {
-               if (lastSessionFetch == -1L) {
-                       return;
-               }
-
-               long currentTime = System.currentTimeMillis();
-               if (currentTime >= lastSessionFetch + timeToRelease) {
-                       confluenceClient.close();
-                       confluenceClient = null;
-                       lastSessionFetch = -1L;
-               }
-       }
-
-       @Override
-       public int getMaxDocumentRequest() {
-               return super.getMaxDocumentRequest();
-       }
-
-       /**
-        * Return the list of relationship types that this connector recognizes.
-        *
-        * @return the list.
-        */
-       @Override
-       public String[] getRelationshipTypes() {
-               return new String[] {};
-       }
-
-       private void fillInServerConfigurationMap(Map<String, String> serverMap,
-                       IPasswordMapperActivity mapper, ConfigParams 
parameters) {
-               String confluenceProtocol = parameters
-                               
.getParameter(ConfluenceConfiguration.Server.PROTOCOL);
-               String confluenceHost = parameters
-                               
.getParameter(ConfluenceConfiguration.Server.HOST);
-               String confluencePort = parameters
-                               
.getParameter(ConfluenceConfiguration.Server.PORT);
-               String confluencePath = parameters
-                               
.getParameter(ConfluenceConfiguration.Server.PATH);
-               String confluenceUsername = parameters
-                               
.getParameter(ConfluenceConfiguration.Server.USERNAME);
-               String confluencePassword = parameters
-                               
.getObfuscatedParameter(ConfluenceConfiguration.Server.PASSWORD);
-
-               if (confluenceProtocol == null)
-                       confluenceProtocol = 
ConfluenceConfiguration.Server.PROTOCOL_DEFAULT_VALUE;
-               if (confluenceHost == null)
-                       confluenceHost = 
ConfluenceConfiguration.Server.HOST_DEFAULT_VALUE;
-               if (confluencePort == null)
-                       confluencePort = 
ConfluenceConfiguration.Server.PORT_DEFAULT_VALUE;
-               if (confluencePath == null)
-                       confluencePath = 
ConfluenceConfiguration.Server.PATH_DEFAULT_VALUE;
-
-               if (confluenceUsername == null)
-                       confluenceUsername = 
ConfluenceConfiguration.Server.USERNAME_DEFAULT_VALUE;
-               if (confluencePassword == null)
-                       confluencePassword = 
ConfluenceConfiguration.Server.PASSWORD_DEFAULT_VALUE;
-               else
-                       confluencePassword = 
mapper.mapPasswordToKey(confluencePassword);
-
-               serverMap.put(PARAMETER_PREFIX
-                               + ConfluenceConfiguration.Server.PROTOCOL, 
confluenceProtocol);
-               serverMap.put(PARAMETER_PREFIX + 
ConfluenceConfiguration.Server.HOST,
-                               confluenceHost);
-               serverMap.put(PARAMETER_PREFIX + 
ConfluenceConfiguration.Server.PORT,
-                               confluencePort);
-               serverMap.put(PARAMETER_PREFIX + 
ConfluenceConfiguration.Server.PATH,
-                               confluencePath);
-               serverMap.put(PARAMETER_PREFIX
-                               + ConfluenceConfiguration.Server.USERNAME, 
confluenceUsername);
-               serverMap.put(PARAMETER_PREFIX
-                               + ConfluenceConfiguration.Server.PASSWORD, 
confluencePassword);
-       }
-
-       @Override
-       public void viewConfiguration(IThreadContext threadContext,
-                       IHTTPOutput out, Locale locale, ConfigParams parameters)
-                       throws ManifoldCFException, IOException {
-               Map<String, String> paramMap = new HashMap<String, String>();
-
-               /* Fill server configuration parameters */
-               fillInServerConfigurationMap(paramMap, out, parameters);
-
-               Messages.outputResourceWithVelocity(out, locale, 
VIEW_CONFIG_FORWARD,
-                               paramMap, true);
-       }
-
-       @Override
-       public void outputConfigurationHeader(IThreadContext threadContext,
-                       IHTTPOutput out, Locale locale, ConfigParams parameters,
-                       List<String> tabsArray) throws ManifoldCFException, 
IOException {
-               // Add the Server tab
-               tabsArray.add(Messages.getString(locale, 
CONF_SERVER_TAB_PROPERTY));
-               // Map the parameters
-               Map<String, String> paramMap = new HashMap<String, String>();
-
-               /* Fill server configuration parameters */
-               fillInServerConfigurationMap(paramMap, out, parameters);
-
-               // Output the Javascript - only one Velocity template for all 
tabs
-               Messages.outputResourceWithVelocity(out, locale,
-                               EDIT_CONFIG_HEADER_FORWARD, paramMap, true);
-       }
-
-       @Override
-       public void outputConfigurationBody(IThreadContext threadContext,
-                       IHTTPOutput out, Locale locale, ConfigParams parameters,
-                       String tabName) throws ManifoldCFException, IOException 
{
-
-               // Call the Velocity templates for each tab
-               Map<String, String> paramMap = new HashMap<String, String>();
-               // Set the tab name
-               paramMap.put("TabName", tabName);
-
-               // Fill in the parameters
-               fillInServerConfigurationMap(paramMap, out, parameters);
-
-               // Server tab
-               Messages.outputResourceWithVelocity(out, locale,
-                               EDIT_CONFIG_FORWARD_SERVER, paramMap, true);
-
-       }
-
-       /*
-        * Repository specification post handle, (server and proxy & client 
secret
-        * etc)
-        * 
-        * @see
-        * 
org.apache.manifoldcf.core.connector.BaseConnector#processConfigurationPost
-        * (org.apache.manifoldcf.core.interfaces.IThreadContext,
-        * org.apache.manifoldcf.core.interfaces.IPostParameters,
-        * org.apache.manifoldcf.core.interfaces.ConfigParams)
-        */
-       @Override
-       public String processConfigurationPost(IThreadContext threadContext,
-                       IPostParameters variableContext, ConfigParams 
parameters)
-                       throws ManifoldCFException {
-
-               String confluenceProtocol = variableContext
-                               .getParameter(PARAMETER_PREFIX
-                                               + 
ConfluenceConfiguration.Server.PROTOCOL);
-               if (confluenceProtocol != null)
-                       
parameters.setParameter(ConfluenceConfiguration.Server.PROTOCOL,
-                                       confluenceProtocol);
-
-               String confluenceHost = 
variableContext.getParameter(PARAMETER_PREFIX
-                               + ConfluenceConfiguration.Server.HOST);
-               if (confluenceHost != null)
-                       
parameters.setParameter(ConfluenceConfiguration.Server.HOST,
-                                       confluenceHost);
-
-               String confluencePort = 
variableContext.getParameter(PARAMETER_PREFIX
-                               + ConfluenceConfiguration.Server.PORT);
-               if (confluencePort != null)
-                       
parameters.setParameter(ConfluenceConfiguration.Server.PORT,
-                                       confluencePort);
-
-               String confluencePath = 
variableContext.getParameter(PARAMETER_PREFIX
-                               + ConfluenceConfiguration.Server.PATH);
-               if (confluencePath != null)
-                       
parameters.setParameter(ConfluenceConfiguration.Server.PATH,
-                                       confluencePath);
-
-               String confluenceUsername = variableContext
-                               .getParameter(PARAMETER_PREFIX
-                                               + 
ConfluenceConfiguration.Server.USERNAME);
-               if (confluenceUsername != null)
-                       
parameters.setParameter(ConfluenceConfiguration.Server.USERNAME,
-                                       confluenceUsername);
-
-               String confluencePassword = variableContext
-                               .getParameter(PARAMETER_PREFIX
-                                               + 
ConfluenceConfiguration.Server.PASSWORD);
-               if (confluencePassword != null)
-                       parameters.setObfuscatedParameter(
-                                       ConfluenceConfiguration.Server.PASSWORD,
-                                       
variableContext.mapKeyToPassword(confluencePassword));
-
-               /* null means process configuration has been successful */
-               return null;
-       }
-
-       /**
-        * <p>
-        * Fill the configured spaces into the map
-        * </p>
-        * 
-        * @param newMap
-        * @param ds
-        */
-       private void fillInConfSpacesSpecificationMap(Map<String, Object> 
newMap,
-                       ConfluenceSpecification cs) {
-
-               
newMap.put(ConfluenceConfiguration.Specification.SPACES.toUpperCase(),
-                               cs.getSpaces());
-       }
-
-       /**
-        * <p>
-        * Fill the pages configuration into the map
-        * </p>
-        * 
-        * @param newMap
-        * @param ds
-        */
-       private void fillInConfPagesSpecificationMap(Map<String, Object> newMap,
-                       ConfluenceSpecification cs) {
-
-               newMap.put(
-                               
ConfluenceConfiguration.Specification.PROCESS_ATTACHMENTS_ATTRIBUTE_KEY
-                                               .toUpperCase(), 
cs.isProcessAttachments());
-               return;
-
-       }
-
-       @Override
-       public void viewSpecification(IHTTPOutput out, Locale locale,
-                       Specification ds, int connectionSequenceNumber)
-                       throws ManifoldCFException, IOException {
-
-               Map<String, Object> paramMap = new HashMap<String, Object>();
-               paramMap.put("SeqNum", 
Integer.toString(connectionSequenceNumber));
-
-               ConfluenceSpecification cs = ConfluenceSpecification.from(ds);
-
-               fillInConfSpacesSpecificationMap(paramMap, cs);
-               fillInConfPagesSpecificationMap(paramMap, cs);
-
-               Messages.outputResourceWithVelocity(out, locale, 
VIEW_SPEC_FORWARD,
-                               paramMap);
-       }
-
-       /*
-        * Handle job specification post
-        * 
-        * @see 
org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector#
-        * processSpecificationPost
-        * (org.apache.manifoldcf.core.interfaces.IPostParameters,
-        * org.apache.manifoldcf.crawler.interfaces.DocumentSpecification)
-        */
-
-       @Override
-       public String processSpecificationPost(IPostParameters variableContext,
-                       Locale locale, Specification ds, int 
connectionSequenceNumber)
-                       throws ManifoldCFException {
-
-               String seqPrefix = "s" + connectionSequenceNumber + "_";
-
-               String xc = variableContext.getParameter(seqPrefix + 
"spacescount");
-               if (xc != null) {
-                       // Delete all preconfigured spaces
-                       int i = 0;
-                       while (i < ds.getChildCount()) {
-                               SpecificationNode sn = ds.getChild(i);
-                               if (sn.getType().equals(
-                                               
ConfluenceConfiguration.Specification.SPACES))
-                                       ds.removeChild(i);
-                               else
-                                       i++;
-                       }
-
-                       SpecificationNode spaces = new SpecificationNode(
-                                       
ConfluenceConfiguration.Specification.SPACES);
-                       ds.addChild(ds.getChildCount(), spaces);
-                       int spacesCount = Integer.parseInt(xc);
-                       i = 0;
-                       while (i < spacesCount) {
-                               String spaceDescription = "_" + 
Integer.toString(i);
-                               String spaceOpName = seqPrefix + "spaceop" + 
spaceDescription;
-                               xc = variableContext.getParameter(spaceOpName);
-                               if (xc != null && xc.equals("Delete")) {
-                                       // Next row
-                                       i++;
-                                       continue;
-                               }
-                               // Get the stuff we need
-                               String spaceKey = 
variableContext.getParameter(seqPrefix
-                                               + "space" + spaceDescription);
-                               SpecificationNode node = new SpecificationNode(
-                                               
ConfluenceConfiguration.Specification.SPACE);
-                               node.setAttribute(
-                                               
ConfluenceConfiguration.Specification.SPACE_KEY_ATTRIBUTE,
-                                               spaceKey);
-                               spaces.addChild(spaces.getChildCount(), node);
-                               i++;
-                       }
-
-                       String op = variableContext.getParameter(seqPrefix + 
"spaceop");
-                       if (op != null && op.equals("Add")) {
-                               String spaceSpec = 
variableContext.getParameter(seqPrefix
-                                               + "space");
-                               SpecificationNode node = new SpecificationNode(
-                                               
ConfluenceConfiguration.Specification.SPACE);
-                               node.setAttribute(
-                                               
ConfluenceConfiguration.Specification.SPACE_KEY_ATTRIBUTE,
-                                               spaceSpec);
-                               spaces.addChild(spaces.getChildCount(), node);
-                       }
-               }
-
-               /* Delete pages configuration */
-               int i = 0;
-               while (i < ds.getChildCount()) {
-                       SpecificationNode sn = ds.getChild(i);
-                       if (sn.getType()
-                                       
.equals(ConfluenceConfiguration.Specification.PAGES))
-                               ds.removeChild(i);
-                       else
-                               i++;
-               }
-
-               SpecificationNode pages = new SpecificationNode(
-                               ConfluenceConfiguration.Specification.PAGES);
-               ds.addChild(ds.getChildCount(), pages);
-
-               String procAttachments = variableContext
-                               .getParameter(seqPrefix
-                                               + 
ConfluenceConfiguration.Specification.PROCESS_ATTACHMENTS_ATTRIBUTE_KEY);
-               if (procAttachments != null && !procAttachments.isEmpty()) {
-                       pages.setAttribute(
-                                       
ConfluenceConfiguration.Specification.PROCESS_ATTACHMENTS_ATTRIBUTE_KEY,
-                                       String.valueOf(procAttachments));
-               }
-
-               return null;
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see 
org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector#
-        * outputSpecificationBody
-        * (org.apache.manifoldcf.core.interfaces.IHTTPOutput, java.util.Locale,
-        * org.apache.manifoldcf.crawler.interfaces.DocumentSpecification,
-        * java.lang.String)
-        */
-       @Override
-       public void outputSpecificationBody(IHTTPOutput out, Locale locale,
-                       Specification ds, int connectionSequenceNumber,
-                       int actualSequenceNumber, String tabName)
-                       throws ManifoldCFException, IOException {
-
-               // Output JIRAQuery tab
-               Map<String, Object> paramMap = new HashMap<String, Object>();
-               paramMap.put("TabName", tabName);
-               paramMap.put("SeqNum", 
Integer.toString(connectionSequenceNumber));
-               paramMap.put("SelectedNum", 
Integer.toString(actualSequenceNumber));
-
-               ConfluenceSpecification cs = ConfluenceSpecification.from(ds);
-
-               fillInConfSpacesSpecificationMap(paramMap, cs);
-               fillInConfPagesSpecificationMap(paramMap, cs);
-               Messages.outputResourceWithVelocity(out, locale,
-                               EDIT_SPEC_FORWARD_SPACES, paramMap);
-
-               Messages.outputResourceWithVelocity(out, locale,
-                               EDIT_SPEC_FORWARD_CONF_PAGES, paramMap);
-       }
-
-       /*
-        * Header for the specification
-        * 
-        * @see 
org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector#
-        * outputSpecificationHeader
-        * (org.apache.manifoldcf.core.interfaces.IHTTPOutput, java.util.Locale,
-        * org.apache.manifoldcf.crawler.interfaces.DocumentSpecification,
-        * java.util.List)
-        */
-       @Override
-       public void outputSpecificationHeader(IHTTPOutput out, Locale locale,
-                       Specification ds, int connectionSequenceNumber,
-                       List<String> tabsArray) throws ManifoldCFException, 
IOException {
-
-               tabsArray.add(Messages.getString(locale, 
CONF_SPACES_TAB_PROPERTY));
-               tabsArray.add(Messages.getString(locale, 
CONF_PAGES_TAB_PROPERTY));
-
-               Map<String, Object> paramMap = new HashMap<String, Object>();
-               paramMap.put("SeqNum", 
Integer.toString(connectionSequenceNumber));
-
-               Messages.outputResourceWithVelocity(out, locale,
-                               EDIT_SPEC_HEADER_FORWARD, paramMap);
-       }
-
-       /*
-        * Adding seed documents
-        * 
-        * @see 
org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector#
-        * addSeedDocuments
-        * (org.apache.manifoldcf.crawler.interfaces.ISeedingActivity,
-        * org.apache.manifoldcf.crawler.interfaces.DocumentSpecification, long,
-        * long, int)
-        */
-       public String addSeedDocuments(ISeedingActivity activities,
-                       Specification spec, String lastSeedVersion, long 
seedTime,
-                       int jobMode) throws ManifoldCFException, 
ServiceInterruption {
-
-               if (!isConnected()) {
-                       initConfluenceClient();
-               }
-
-               try {
-
-                       /*
-                        * Not uses delta seeding because Confluence can't be 
queried using
-                        * dates or in a ordered way, only start and limit 
which can cause
-                        * problems if an already indexed document is deleted, 
because we
-                        * will miss some to-be indexed docs due to the last 
start parameter
-                        * stored in the last execution
-                        */
-                       // if(lastSeedVersion != null && 
!lastSeedVersion.isEmpty()) {
-                       // StringTokenizer tokenizer = new
-                       // StringTokenizer(lastSeedVersion,"|");
-                       //
-                       // lastStart = new Long(lastSeedVersion);
-                       // }
-
-                       ConfluenceSpecification confluenceSpecification = 
ConfluenceSpecification
-                                       .from(spec);
-                       List<String> spaceKeys = 
confluenceSpecification.getSpaces();
-
-                       if (spaceKeys.isEmpty()) {
-                               logger.info("No spaces configured. Processing 
all spaces");
-                               addSeedDocumentsForSpace(Optional.<String> 
absent(),
-                                               activities, 
confluenceSpecification, lastSeedVersion,
-                                               seedTime, jobMode);
-                       } else {
-                               for (String space : spaceKeys) {
-                                       logger.info("Processing configured 
space {}", space);
-                                       
addSeedDocumentsForSpace(Optional.<String> of(space),
-                                                       activities, 
confluenceSpecification,
-                                                       lastSeedVersion, 
seedTime, jobMode);
-                               }
-                       }
-
-                       return "";
-               } catch (Exception e) {
-                       handleConfluenceDownException(e, "seeding");
-                       return null;
-               }
-       }
-
-       /**
-        * <p>
-        * Add seed documents for a given optional space
-        * </p>
-        * 
-        * @throws ServiceInterruption
-        * @throws ManifoldCFException
-        */
-       private void addSeedDocumentsForSpace(Optional<String> space,
-                       ISeedingActivity activities,
-                       ConfluenceSpecification confluenceSpec, String 
lastSeedVersion,
-                       long seedTime, int jobMode) throws ManifoldCFException,
-                       ServiceInterruption {
-
-               long lastStart = 0;
-               long defaultSize = 50;
-
-               if (Logging.connectors != null && 
Logging.connectors.isDebugEnabled()) {
-                       String spaceDesc = space.isPresent() ? "space with key "
-                                       + space.get() : "all the spaces";
-                       Logging.connectors.debug(MessageFormat.format(
-                                       "Starting from {0} and size {1} for 
{2}", new Object[] {
-                                                       lastStart, defaultSize, 
spaceDesc }));
-               }
-
-               try {
-                       Boolean isLast = true;
-                       do {
-                               final ConfluenceResponse<Page> response = 
confluenceClient.getPages(
-                                               (int) lastStart, (int) 
defaultSize, space);
-
-                               int count = 0;
-                               for (Page page : response.getResults()) {
-
-                                       
activities.addSeedDocument(page.getId());
-                                       if 
(confluenceSpec.isProcessAttachments()) {
-                                               processSeedAttachments(page, 
activities);
-                                       }
-                                       count++;
-                               }
-                               if (Logging.connectors != null
-                                               && 
Logging.connectors.isDebugEnabled())
-                                       
Logging.connectors.debug(MessageFormat.format(
-                                                       "Fetched and added {0} 
seed documents",
-                                                       new Object[] { new 
Integer(count) }));
-
-                               lastStart += count;
-                               isLast = response.isLast();
-                               if (Logging.connectors != null
-                                               && 
Logging.connectors.isDebugEnabled())
-                                       
Logging.connectors.debug(MessageFormat.format(
-                                                       "New start {0} and size 
{1}", new Object[] {
-                                                                       
lastStart, defaultSize }));
-                       } while (!isLast);
-
-               } catch (Exception e) {
-                       handleConfluenceDownException(e, "seeding");
-               }
-
-       }
-
-       /**
-        * <p>
-        * Process seed attachments for the given page
-        * </p>
-        * 
-        * @param page
-        * @param activities
-        */
-       private void processSeedAttachments(Page page, ISeedingActivity 
activities)
-                       throws ManifoldCFException, ServiceInterruption {
-               long lastStart = 0;
-               long defaultSize = 50;
-
-               if (Logging.connectors != null && 
Logging.connectors.isDebugEnabled()) {
-                       Logging.connectors
-                                       .debug(MessageFormat
-                                                       .format("Processing 
page {} attachments starting from {} and size {}",
-                                                                       new 
Object[] { page.getId(), lastStart,
-                                                                               
        defaultSize }));
-               }
-
-               try {
-                       Boolean isLast = true;
-                       do {
-                               final ConfluenceResponse<Attachment> response = 
confluenceClient
-                                               
.getPageAttachments(page.getId(), (int) lastStart,
-                                                               (int) 
defaultSize);
-
-                               int count = 0;
-                               for (Page resultPage : response.getResults()) {
-                                       
activities.addSeedDocument(ConfluenceUtil
-                                                       
.generateRepositoryDocumentIdentifier(
-                                                                       
resultPage.getId(), page.getId()));
-                                       count++;
-                               }
-
-                               if (Logging.connectors != null
-                                               && 
Logging.connectors.isDebugEnabled())
-                                       Logging.connectors
-                                                       .debug(MessageFormat
-                                                                       
.format("Fetched and added {} seed document attachments for page {}",
-                                                                               
        new Object[] { new Integer(count),
-                                                                               
                        page.getId() }));
-
-                               lastStart += count;
-                               isLast = response.isLast();
-                               if (Logging.connectors != null
-                                               && 
Logging.connectors.isDebugEnabled())
-                                       
Logging.connectors.debug(MessageFormat.format(
-                                                       "New start {0} and size 
{1}", new Object[] {
-                                                                       
lastStart, defaultSize }));
-                       } while (!isLast);
-
-               } catch (Exception e) {
-                       handleConfluenceDownException(e, "seeding");
-               }
-       }
-
-       protected static void handleConfluenceDownException(Exception e,
-                       String context) throws ManifoldCFException, 
ServiceInterruption {
-               long currentTime = System.currentTimeMillis();
-
-               // Server doesn't appear to by up. Try for a brief time then 
give up.
-               String message = "Server appears down during " + context + ": "
-                               + e.getMessage();
-               Logging.connectors.warn(message, e);
-               throw new ServiceInterruption(message, e, currentTime
-                               + interruptionRetryTime, -1L, 3, true);
-       }
-
-       /*
-        * Process documents
-        * 
-        * @see 
org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector#
-        * processDocuments(java.lang.String[], java.lang.String[],
-        * org.apache.manifoldcf.crawler.interfaces.IProcessActivity,
-        * org.apache.manifoldcf.crawler.interfaces.DocumentSpecification,
-        * boolean[])
-        */
-       @Override
-       public void processDocuments(String[] documentIdentifiers,
-                       IExistingVersions statuses, Specification spec,
-                       IProcessActivity activities, int jobMode,
-                       boolean usesDefaultAuthority) throws 
ManifoldCFException,
-                       ServiceInterruption {
-
-               if(Logging.connectors != null && 
Logging.connectors.isDebugEnabled())
-                       Logging.connectors
-                               .debug("Process Confluence documents: Inside 
processDocuments");
-
-               for (int i = 0; i < documentIdentifiers.length; i++) {
-                       String pageId = documentIdentifiers[i];
-                       String version = 
statuses.getIndexedVersionString(pageId);
-
-                       long startTime = System.currentTimeMillis();
-                       String errorCode = "OK";
-                       String errorDesc = StringUtils.EMPTY;
-                       ProcessResult pResult = null;
-                       boolean doLog = true;
-
-                       try {
-                               if (Logging.connectors != null && 
Logging.connectors.isDebugEnabled()) {
-                                       Logging.connectors
-                                                       .debug("Confluence: 
Processing document identifier '"
-                                                                       + 
pageId + "'");
-                               }
-
-                               /* Ensure Confluence client is connected */
-                               if (!isConnected()) {
-                                       initConfluenceClient();
-                               }
-
-                               if (ConfluenceUtil.isAttachment(pageId)) {
-                                       pResult = 
processPageAsAttachment(pageId, version,
-                                                       activities, doLog);
-                               }
-                               else {
-                                       pResult = processPage(pageId, version, 
activities, doLog,
-                                                       Maps.<String, String> 
newHashMap());
-                               }
-                       } catch (IOException ioe) {
-                               handleIOException(ioe);
-                       } catch (Exception e) {
-                               handleException(e);
-                       }
-
-                       finally {
-                               if (doLog){
-                                       if(pResult.errorCode != null && 
!pResult.errorCode.isEmpty()){
-                                               activities.recordActivity(new 
Long(startTime),
-                                                               ACTIVITY_READ, 
pResult.fileSize, pageId, pResult.errorCode,
-                                                                       
pResult.errorDescription, null);
-                                       }else{
-                                               activities.recordActivity(new 
Long(startTime),
-                                                               ACTIVITY_READ, 
pResult.fileSize, pageId, errorCode,
-                                                                       
errorDesc, null);
-                                       }
-                               }
-                       }
-
-               }
-       }
-
-       /**
-        * <p>
-        * Process the specific page
-        * </p>
-        * 
-        * @param pageId
-        *            The pageId being an attachment
-        * @param version
-        *            The version of the page
-        * @param activities
-        * @param doLog
-        * @throws ManifoldCFException
-        * @throws IOException
-        * @throws ServiceInterruption
-        */
-       private ProcessResult processPage(String pageId, String version,
-                       IProcessActivity activities, boolean doLog,
-                       Map<String, String> extraProperties) throws 
ManifoldCFException,
-                       ServiceInterruption, IOException {
-               Page page = confluenceClient.getPage(pageId);
-               return processPageInternal(page, pageId, version, activities, 
doLog,
-                               extraProperties);
-       }
-
-       /**
-        * <p>
-        * Process the specific attachment
-        * </p>
-        * 
-        * @param pageId
-        *            The pageId being an attachment
-        * @param version
-        *            The version of the page
-        * @param activities
-        * @param doLog
-        * @throws IOException
-        * @throws ServiceInterruption
-        */
-       private ProcessResult processPageAsAttachment(String pageId, String 
version,
-                       IProcessActivity activities, boolean doLog)
-                       throws ManifoldCFException, ServiceInterruption, 
IOException {
-
-               String[] ids = ConfluenceUtil.getAttachmentAndPageId(pageId);
-               Attachment attachment = confluenceClient.getAttachment(ids[0]);
-               Map<String, String> extraProperties = Maps.newHashMap();
-               extraProperties.put("attachedBy", ids[1]);
-               return processPageInternal(attachment, pageId, version, 
activities, doLog,
-                               extraProperties);
-       }
-
-       /**
-        * <p>
-        * Process the specific page
-        * </p>
-        * 
-        * @param pageId
-        *            The pageId being an attachment
-        * @param manifoldDocumentIdentifier
-        * @param version
-        *            The version of the page
-        * @param activities
-        * @param doLog
-        * @throws ManifoldCFException
-        * @throws IOException
-        * @throws ServiceInterruption
-        */
-       private ProcessResult processPageInternal(Page page,
-                       String manifoldDocumentIdentifier, String version,
-                       IProcessActivity activities, boolean doLog,
-                       Map<String, String> extraProperties) throws 
ManifoldCFException,
-                       ServiceInterruption, IOException {
-
-                               
-               /* Remove page if it has no content */
-               /*
-                * Page does not have content if there was an error trying to 
get the
-                * page
-                */
-               if (!page.hasContent()) {
-                       activities.deleteDocument(manifoldDocumentIdentifier);
-                       return new ProcessResult(page.getLength(), "DELETED", 
"");
-               }
-               if (Logging.connectors != null && 
Logging.connectors.isDebugEnabled()) {
-                       Logging.connectors.debug("Confluence: This content 
exists: "
-                                       + page.getId());
-               }
-
-               RepositoryDocument rd = new RepositoryDocument();
-               Date createdDate = page.getCreatedDate();
-               Date lastModified = page.getLastModifiedDate();
-               DateFormat df = DateFormat.getDateTimeInstance();
-
-               /*
-                * Retain page in Manifold because it has not changed from last 
time
-                * This is needed to keep the identifier in Manifold data, 
because by
-                * default if a document is not retained nor ingested, it will 
be
-                * deleted by the framework
-                */
-               String lastVersion = df.format(lastModified);
-               
-               if 
(!activities.checkDocumentNeedsReindexing(manifoldDocumentIdentifier, 
lastVersion)) {
-                       return new ProcessResult(page.getLength(), "RETAINED", 
"");
-               }
-               
-               if (!activities.checkLengthIndexable(page.getLength())){
-                       activities.noDocument(page.getId(), lastVersion);
-                       String errorCode = IProcessActivity.EXCLUDED_LENGTH;
-                       String errorDesc = "Excluding document because of 
length ("+page.getLength()+")";
-                       return new ProcessResult(page.getLength(), errorCode, 
errorDesc);
-               }
-
-               if (!activities.checkMimeTypeIndexable(page.getMediaType())) {
-                       activities.noDocument(page.getId(), lastVersion);
-                       String errorCode = IProcessActivity.EXCLUDED_MIMETYPE;
-                       String errorDesc = "Excluding document because of mime 
type ("+page.getMediaType()+")";
-                       return new ProcessResult(page.getLength(), errorCode, 
errorDesc);
-               }
-
-               if (!activities.checkDateIndexable(lastModified)) {
-                       activities.noDocument(page.getId(), lastVersion);
-                       String errorCode = IProcessActivity.EXCLUDED_DATE;
-                       String errorDesc = "Excluding document because of date 
("+lastModified+")";
-                       return new ProcessResult(page.getLength(), errorCode, 
errorDesc);
-               }
-
-               if (!activities.checkURLIndexable(page.getWebUrl())) {
-                       activities.noDocument(page.getId(), lastVersion);
-                       String errorCode = IProcessActivity.EXCLUDED_URL;
-                       String errorDesc = "Excluding document because of URL 
('"+page.getWebUrl()+"')";
-                       return new ProcessResult(page.getLength(), errorCode, 
errorDesc);
-               }
-
-               /* Add repository document information */
-               rd.setMimeType(page.getMediaType());
-               if (createdDate != null)
-                       rd.setCreatedDate(createdDate);
-               if (lastModified != null)
-                       rd.setModifiedDate(lastModified);
-               rd.setIndexingDate(new Date());
-
-               /* Adding Page Metadata */
-               Map<String, Object> pageMetadata = page.getMetadataAsMap();
-               for (Entry<String, Object> entry : pageMetadata.entrySet()) {
-                       if(entry.getValue() instanceof List) {
-                               List<?> list = (List<?>)entry.getValue();
-                               rd.addField(entry.getKey(), list.toArray(new 
String[list.size()]));
-                       }
-                       else {
-                               rd.addField(entry.getKey(), 
entry.getValue().toString());
-                       }
-               }
-
-               /* Adding extra properties */
-               for (Entry<String, String> entry : extraProperties.entrySet()) {
-                       rd.addField(entry.getKey(), entry.getValue());
-               }
-
-               String documentURI = page.getWebUrl();
-
-               /* Set repository document ACLs */
-               rd.setSecurityACL(RepositoryDocument.SECURITY_TYPE_DOCUMENT,
-                               new String[] { page.getSpace() });
-               rd.setSecurityDenyACL(RepositoryDocument.SECURITY_TYPE_DOCUMENT,
-                               new String[] { defaultAuthorityDenyToken });
-
-               rd.setBinary(page.getContentStream(), page.getLength());
-               rd.addField("size", String.valueOf(page.getLength()));
-
-               /* Ingest document */
-               
activities.ingestDocumentWithException(manifoldDocumentIdentifier,
-                               lastVersion, documentURI, rd);
-               
-               return new ProcessResult(page.getLength(), null, null);
-       }
-
-       /**
-        * <p>
-        * Handles IO Exception to manage whether the exception is an 
interruption
-        * so that the process needs to be executed again later on
-        * </p>
-        * 
-        * @param e
-        *            The Exception
-        * @throws ManifoldCFException
-        * @throws ServiceInterruption
-        */
-       private static void handleIOException(IOException e)
-                       throws ManifoldCFException, ServiceInterruption {
-               if (!(e instanceof java.net.SocketTimeoutException)
-                               && (e instanceof InterruptedIOException)) {
-                       throw new ManifoldCFException("Interrupted: " + 
e.getMessage(), e,
-                                       ManifoldCFException.INTERRUPTED);
-               }
-               Logging.connectors.warn("IO exception: " + e.getMessage(), e);
-               long currentTime = System.currentTimeMillis();
-               throw new ServiceInterruption("IO exception: " + 
e.getMessage(), e,
-                               currentTime + 300000L, currentTime + 3 * 60 * 
60000L, -1, false);
-       }
-
-       /**
-        * <p>
-        * Handles general exceptions
-        * </p>
-        * 
-        * @param e
-        *            The Exception
-        * @throws ManifoldCFException
-        */
-       private static void handleException(Exception e) throws 
ManifoldCFException {
-               Logging.connectors.warn("Exception: " + e.getMessage(), e);
-               throw new ManifoldCFException("Exception: " + e.getMessage(), e,
-                               
ManifoldCFException.REPOSITORY_CONNECTION_ERROR);
-
-       }
-       
-       private class ProcessResult{
-               private long fileSize;
-               private String errorCode;
-               private String errorDescription;
-               
-               private ProcessResult(long fileSize, String errorCode, String 
errorDescription){
-                       this.fileSize = fileSize;
-                       this.errorCode = errorCode;
-                       this.errorDescription = errorDescription;
-               }
-       }
-
-       /**
-        * <p>
-        * Internal private class used to parse and keep the specification
-        * configuration in object format
-        * </p>
-        * 
-        * @author Antonio David Perez Morales <[email protected]>
-        *
-        */
-       private static class ConfluenceSpecification {
-               private List<String> spaces;
-               private Boolean processAttachments = false;
-
-               /**
-                * <p>
-                * Returns if attachments should be processed
-                * </p>
-                * 
-                * @return a {@code Boolean} indicating if the attachments 
should be
-                *         processed or not
-                */
-               public Boolean isProcessAttachments() {
-                       return this.processAttachments;
-               }
-
-               /**
-                * <p>
-                * Returns the list of configured spaces or an empty list 
meaning that
-                * all spaces should be processed
-                * </p>
-                * 
-                * @return a {@code List<String>} of configured spaces
-                */
-               public List<String> getSpaces() {
-                       return this.spaces;
-               }
-
-               public static ConfluenceSpecification from(Specification spec) {
-                       ConfluenceSpecification cs = new 
ConfluenceSpecification();
-                       cs.spaces = Lists.newArrayList();
-                       for (int i = 0, len = spec.getChildCount(); i < len; 
i++) {
-                               SpecificationNode sn = spec.getChild(i);
-                               if (sn.getType().equals(
-                                               
ConfluenceConfiguration.Specification.SPACES)) {
-                                       for (int j = 0, sLen = 
sn.getChildCount(); j < sLen; j++) {
-                                               SpecificationNode specNode = 
sn.getChild(j);
-                                               if (specNode.getType().equals(
-                                                               
ConfluenceConfiguration.Specification.SPACE)) {
-                                                       cs.spaces
-                                                                       
.add(specNode
-                                                                               
        
.getAttributeValue(ConfluenceConfiguration.Specification.SPACE_KEY_ATTRIBUTE));
-
-                                               }
-                                       }
-
-                               } else if (sn.getType().equals(
-                                               
ConfluenceConfiguration.Specification.PAGES)) {
-                                       String s = sn
-                                                       
.getAttributeValue(ConfluenceConfiguration.Specification.PROCESS_ATTACHMENTS_ATTRIBUTE_KEY);
-                                       cs.processAttachments = 
Boolean.valueOf(s);
-                               }
-                       }
+  /*
+   * Prefix for Confluence configuration and specification parameters
+   */
+  private static final String PARAMETER_PREFIX = "confluence_";
+
+  /* Configuration tabs */
+  private static final String CONF_SERVER_TAB_PROPERTY = 
"ConfluenceRepositoryConnector.Server";
+
+  /* Specification tabs */
+  private static final String CONF_SPACES_TAB_PROPERTY = 
"ConfluenceRepositoryConnector.Spaces";
+  private static final String CONF_PAGES_TAB_PROPERTY = 
"ConfluenceRepositoryConnector.Pages";
+
+  // pages & js
+  // Template names for Confluence configuration
+  /**
+   * Forward to the javascript to check the configuration parameters
+   */
+  private static final String EDIT_CONFIG_HEADER_FORWARD = 
"editConfiguration_conf.js";
+  /**
+   * Server tab template
+   */
+  private static final String EDIT_CONFIG_FORWARD_SERVER = 
"editConfiguration_conf_server.html";
+
+  /**
+   * Forward to the HTML template to view the configuration parameters
+   */
+  private static final String VIEW_CONFIG_FORWARD = 
"viewConfiguration_conf.html";
+
+  // Template names for Confluence job specification
+  /**
+   * Forward to the javascript to check the specification parameters for the
+   * job
+   */
+  private static final String EDIT_SPEC_HEADER_FORWARD = 
"editSpecification_conf.js";
+  /**
+   * Forward to the template to edit the spaces for the job
+   */
+  private static final String EDIT_SPEC_FORWARD_SPACES = 
"editSpecification_confSpaces.html";
+
+  /**
+   * Forward to the template to edit the pages configuration for the job
+   */
+  private static final String EDIT_SPEC_FORWARD_CONF_PAGES = 
"editSpecification_confPages.html";
+
+  /**
+   * Forward to the template to view the specification parameters for the job
+   */
+  private static final String VIEW_SPEC_FORWARD = 
"viewSpecification_conf.html";
+
+  protected long lastSessionFetch = -1L;
+  protected static final long timeToRelease = 300000L;
+
+  protected final static long interruptionRetryTime = 5L * 60L * 1000L;
+
+  private Logger logger = LoggerFactory
+      .getLogger(ConfluenceRepositoryConnector.class);
+
+  /* Confluence instance parameters */
+  protected String protocol = null;
+  protected String host = null;
+  protected String port = null;
+  protected String path = null;
+  protected String username = null;
+  protected String password = null;
+
+  protected ConfluenceClient confluenceClient = null;
+
+  /**
+   * <p>
+   * Default constructor
+   * </p>
+   */
+  public ConfluenceRepositoryConnector() {
+    super();
+  }
+  
+  /**
+   * Set Confluence Client (Mainly for Testing)
+   * 
+   * @param confluenceClient
+   */
+  public void setConfluenceClient(ConfluenceClient confluenceClient){
+    this.confluenceClient = confluenceClient;
+  }
+
+  @Override
+  public String[] getActivitiesList() {
+    return new String[] { ACTIVITY_READ };
+  }
+
+  @Override
+  public String[] getBinNames(String documentIdentifier) {
+    return new String[] { host };
+  }
+
+  /**
+   * Close the connection. Call this before discarding the connection.
+   */
+  @Override
+  public void disconnect() throws ManifoldCFException {
+    if (confluenceClient != null) {
+      confluenceClient = null;
+    }
+
+    protocol = null;
+    host = null;
+    port = null;
+    path = null;
+    username = null;
+    password = null;
+
+  }
+
+  /**
+   * Makes connection to server
+   * 
+   * 
+   */
+  @Override
+  public void connect(ConfigParams configParams) {
+    super.connect(configParams);
+
+    protocol = params.getParameter(ConfluenceConfiguration.Server.PROTOCOL);
+    host = params.getParameter(ConfluenceConfiguration.Server.HOST);
+    port = params.getParameter(ConfluenceConfiguration.Server.PORT);
+    path = params.getParameter(ConfluenceConfiguration.Server.PATH);
+    username = params.getParameter(ConfluenceConfiguration.Server.USERNAME);
+    password = params
+        .getObfuscatedParameter(ConfluenceConfiguration.Server.PASSWORD);
+
+    try {
+      initConfluenceClient();
+    } catch (ManifoldCFException e) {
+      logger.debug(
+          "Not possible to initialize Confluence client. Reason: {}",
+          e.getMessage());
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * Checks if connection is available
+   */
+  @Override
+  public String check() throws ManifoldCFException {
+    try {
+      if (!isConnected()) {
+        initConfluenceClient();
+      }
+      Boolean result = confluenceClient.check();
+      if (result)
+        return super.check();
+      else
+        throw new ManifoldCFException(
+            "Confluence instance could not be reached");
+    } catch (ServiceInterruption e) {
+      return "Connection temporarily failed: " + e.getMessage();
+    } catch (ManifoldCFException e) {
+      return "Connection failed: " + e.getMessage();
+    } catch (Exception e) {
+      return "Connection failed: " + e.getMessage();
+    }
+  }
+
+  /**
+   * <p>
+   * Initialize Confluence client using the configured parameters
+   * 
+   * @throws ManifoldCFException
+   */
+  protected void initConfluenceClient() throws ManifoldCFException {
+    if (confluenceClient == null) {
+
+      if (StringUtils.isEmpty(protocol)) {
+        throw new ManifoldCFException("Parameter "
+            + ConfluenceConfiguration.Server.PROTOCOL
+            + " required but not set");
+      }
+
+      if (Logging.connectors.isDebugEnabled()) {
+        Logging.connectors.debug("Confluence protocol = '" + protocol
+            + "'");
+      }
+
+      if (StringUtils.isEmpty(host)) {
+        throw new ManifoldCFException("Parameter "
+            + ConfluenceConfiguration.Server.HOST
+            + " required but not set");
+      }
+
+      if (Logging.connectors.isDebugEnabled()) {
+        Logging.connectors.debug("Confluence host = '" + host + "'");
+      }
+
+      if (Logging.connectors.isDebugEnabled()) {
+        Logging.connectors.debug("Confluence port = '" + port + "'");
+      }
+
+//      if (StringUtils.isEmpty(path)) {
+//        throw new ManifoldCFException("Parameter "
+//            + ConfluenceConfiguration.Server.PATH
+//            + " required but not set");
+//      }
+
+      if (Logging.connectors.isDebugEnabled()) {
+        Logging.connectors.debug("Confluence path = '" + path + "'");
+      }
+
+      if (Logging.connectors.isDebugEnabled()) {
+        Logging.connectors.debug("Confluence username = '" + username
+            + "'");
+      }
+
+      if (Logging.connectors.isDebugEnabled()) {
+        Logging.connectors
+            .debug("Confluence password '" + password != null ? "set"
+                : "not set" + "'");
+      }
+
+      int portInt;
+      if (port != null && port.length() > 0) {
+        try {
+          portInt = Integer.parseInt(port);
+        } catch (NumberFormatException e) {
+          throw new ManifoldCFException("Bad number: "
+              + e.getMessage(), e);
+        }
+      } else {
+        if (protocol.toLowerCase(Locale.ROOT).equals("http"))
+          portInt = 80;
+        else
+          portInt = 443;
+      }
+
+      /* Generating a client to perform Confluence requests */
+      confluenceClient = new ConfluenceClient(protocol, host, portInt,
+          path, username, password);
+      lastSessionFetch = System.currentTimeMillis();
+    }
+
+  }
+
+  /**
+   * 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 confluenceClient != null;
+  }
+
+  @Override
+  public void poll() throws ManifoldCFException {
+    if (lastSessionFetch == -1L) {
+      return;
+    }
+
+    long currentTime = System.currentTimeMillis();
+    if (currentTime >= lastSessionFetch + timeToRelease) {
+      confluenceClient.close();
+      confluenceClient = null;
+      lastSessionFetch = -1L;
+    }
+  }
+
+  @Override
+  public int getMaxDocumentRequest() {
+    return super.getMaxDocumentRequest();
+  }
+
+  /**
+   * Return the list of relationship types that this connector recognizes.
+   *
+   * @return the list.
+   */
+  @Override
+  public String[] getRelationshipTypes() {
+    return new String[] {};
+  }
+
+  private void fillInServerConfigurationMap(Map<String, String> serverMap,
+      IPasswordMapperActivity mapper, ConfigParams parameters) {
+    String confluenceProtocol = parameters
+        .getParameter(ConfluenceConfiguration.Server.PROTOCOL);
+    String confluenceHost = parameters
+        .getParameter(ConfluenceConfiguration.Server.HOST);
+    String confluencePort = parameters
+        .getParameter(ConfluenceConfiguration.Server.PORT);
+    String confluencePath = parameters
+        .getParameter(ConfluenceConfiguration.Server.PATH);
+    String confluenceUsername = parameters
+        .getParameter(ConfluenceConfiguration.Server.USERNAME);
+    String confluencePassword = parameters
+        .getObfuscatedParameter(ConfluenceConfiguration.Server.PASSWORD);
+
+    if (confluenceProtocol == null)
+      confluenceProtocol = 
ConfluenceConfiguration.Server.PROTOCOL_DEFAULT_VALUE;
+    if (confluenceHost == null)
+      confluenceHost = ConfluenceConfiguration.Server.HOST_DEFAULT_VALUE;
+    if (confluencePort == null)
+      confluencePort = ConfluenceConfiguration.Server.PORT_DEFAULT_VALUE;
+    if (confluencePath == null)
+      confluencePath = ConfluenceConfiguration.Server.PATH_DEFAULT_VALUE;
+
+    if (confluenceUsername == null)
+      confluenceUsername = 
ConfluenceConfiguration.Server.USERNAME_DEFAULT_VALUE;
+    if (confluencePassword == null)
+      confluencePassword = 
ConfluenceConfiguration.Server.PASSWORD_DEFAULT_VALUE;
+    else
+      confluencePassword = mapper.mapPasswordToKey(confluencePassword);
+
+    serverMap.put(PARAMETER_PREFIX
+        + ConfluenceConfiguration.Server.PROTOCOL, confluenceProtocol);
+    serverMap.put(PARAMETER_PREFIX + ConfluenceConfiguration.Server.HOST,
+        confluenceHost);
+    serverMap.put(PARAMETER_PREFIX + ConfluenceConfiguration.Server.PORT,
+        confluencePort);
+    serverMap.put(PARAMETER_PREFIX + ConfluenceConfiguration.Server.PATH,
+        confluencePath);
+    serverMap.put(PARAMETER_PREFIX
+        + ConfluenceConfiguration.Server.USERNAME, confluenceUsername);
+    serverMap.put(PARAMETER_PREFIX
+        + ConfluenceConfiguration.Server.PASSWORD, confluencePassword);
+  }
+
+  @Override
+  public void viewConfiguration(IThreadContext threadContext,
+      IHTTPOutput out, Locale locale, ConfigParams parameters)
+      throws ManifoldCFException, IOException {
+    Map<String, String> paramMap = new HashMap<String, String>();
+
+    /* Fill server configuration parameters */
+    fillInServerConfigurationMap(paramMap, out, parameters);
+
+    Messages.outputResourceWithVelocity(out, locale, VIEW_CONFIG_FORWARD,
+        paramMap, true);
+  }
+
+  @Override
+  public void outputConfigurationHeader(IThreadContext threadContext,
+      IHTTPOutput out, Locale locale, ConfigParams parameters,
+      List<String> tabsArray) throws ManifoldCFException, IOException {
+    // Add the Server tab
+    tabsArray.add(Messages.getString(locale, CONF_SERVER_TAB_PROPERTY));
+    // Map the parameters
+    Map<String, String> paramMap = new HashMap<String, String>();
+
+    /* Fill server configuration parameters */
+    fillInServerConfigurationMap(paramMap, out, parameters);
+
+    // Output the Javascript - only one Velocity template for all tabs
+    Messages.outputResourceWithVelocity(out, locale,
+        EDIT_CONFIG_HEADER_FORWARD, paramMap, true);
+  }
+
+  @Override
+  public void outputConfigurationBody(IThreadContext threadContext,
+      IHTTPOutput out, Locale locale, ConfigParams parameters,
+      String tabName) throws ManifoldCFException, IOException {
+
+    // Call the Velocity templates for each tab
+    Map<String, String> paramMap = new HashMap<String, String>();
+    // Set the tab name
+    paramMap.put("TabName", tabName);
+
+    // Fill in the parameters
+    fillInServerConfigurationMap(paramMap, out, parameters);
+
+    // Server tab
+    Messages.outputResourceWithVelocity(out, locale,
+        EDIT_CONFIG_FORWARD_SERVER, paramMap, true);
+
+  }
+
+  /*
+   * Repository specification post handle, (server and proxy & client secret
+   * etc)
+   * 
+   * @see
+   * 
org.apache.manifoldcf.core.connector.BaseConnector#processConfigurationPost
+   * (org.apache.manifoldcf.core.interfaces.IThreadContext,
+   * org.apache.manifoldcf.core.interfaces.IPostParameters,
+   * org.apache.manifoldcf.core.interfaces.ConfigParams)
+   */
+  @Override
+  public String processConfigurationPost(IThreadContext threadContext,
+      IPostParameters variableContext, ConfigParams parameters)
+      throws ManifoldCFException {
+
+    String confluenceProtocol = variableContext
+        .getParameter(PARAMETER_PREFIX
+            + ConfluenceConfiguration.Server.PROTOCOL);
+    if (confluenceProtocol != null)
+      parameters.setParameter(ConfluenceConfiguration.Server.PROTOCOL,
+          confluenceProtocol);
+
+    String confluenceHost = variableContext.getParameter(PARAMETER_PREFIX
+        + ConfluenceConfiguration.Server.HOST);
+    if (confluenceHost != null)
+      parameters.setParameter(ConfluenceConfiguration.Server.HOST,
+          confluenceHost);
+
+    String confluencePort = variableContext.getParameter(PARAMETER_PREFIX
+        + ConfluenceConfiguration.Server.PORT);
+    if (confluencePort != null)
+      parameters.setParameter(ConfluenceConfiguration.Server.PORT,
+          confluencePort);
+
+    String confluencePath = variableContext.getParameter(PARAMETER_PREFIX
+        + ConfluenceConfiguration.Server.PATH);
+    if (confluencePath != null)
+      parameters.setParameter(ConfluenceConfiguration.Server.PATH,
+          confluencePath);
+
+    String confluenceUsername = variableContext
+        .getParameter(PARAMETER_PREFIX
+            + ConfluenceConfiguration.Server.USERNAME);
+    if (confluenceUsername != null)
+      parameters.setParameter(ConfluenceConfiguration.Server.USERNAME,
+          confluenceUsername);
+
+    String confluencePassword = variableContext
+        .getParameter(PARAMETER_PREFIX
+            + ConfluenceConfiguration.Server.PASSWORD);
+    if (confluencePassword != null)
+      parameters.setObfuscatedParameter(
+          ConfluenceConfiguration.Server.PASSWORD,
+          variableContext.mapKeyToPassword(confluencePassword));
+
+    /* null means process configuration has been successful */
+    return null;
+  }
+
+  /**
+   * <p>
+   * Fill the configured spaces into the map
+   * </p>
+   * 
+   * @param newMap
+   * @param ds
+   */
+  private void fillInConfSpacesSpecificationMap(Map<String, Object> newMap,
+      ConfluenceSpecification cs) {
+
+    newMap.put(ConfluenceConfiguration.Specification.SPACES.toUpperCase(),
+        cs.getSpaces());
+  }
+
+  /**
+   * <p>
+   * Fill the pages configuration into the map
+   * </p>
+   * 
+   * @param newMap
+   * @param ds
+   */
+  private void fillInConfPagesSpecificationMap(Map<String, Object> newMap,
+      ConfluenceSpecification cs) {
+
+    newMap.put(
+        ConfluenceConfiguration.Specification.PROCESS_ATTACHMENTS_ATTRIBUTE_KEY
+            .toUpperCase(), cs.isProcessAttachments());
+    return;
+
+  }
+
+  @Override
+  public void viewSpecification(IHTTPOutput out, Locale locale,
+      Specification ds, int connectionSequenceNumber)
+      throws ManifoldCFException, IOException {
+
+    Map<String, Object> paramMap = new HashMap<String, Object>();
+    paramMap.put("SeqNum", Integer.toString(connectionSequenceNumber));
+
+    ConfluenceSpecification cs = ConfluenceSpecification.from(ds);
+
+    fillInConfSpacesSpecificationMap(paramMap, cs);
+    fillInConfPagesSpecificationMap(paramMap, cs);
+
+    Messages.outputResourceWithVelocity(out, locale, VIEW_SPEC_FORWARD,
+        paramMap);
+  }
+
+  /*
+   * Handle job specification post
+   * 
+   * @see org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector#
+   * processSpecificationPost
+   * (org.apache.manifoldcf.core.interfaces.IPostParameters,
+   * org.apache.manifoldcf.crawler.interfaces.DocumentSpecification)
+   */
+
+  @Override
+  public String processSpecificationPost(IPostParameters variableContext,
+      Locale locale, Specification ds, int connectionSequenceNumber)
+      throws ManifoldCFException {
+
+    String seqPrefix = "s" + connectionSequenceNumber + "_";
+
+    String xc = variableContext.getParameter(seqPrefix + "spacescount");
+    if (xc != null) {
+      // Delete all preconfigured spaces
+      int i = 0;
+      while (i < ds.getChildCount()) {
+        SpecificationNode sn = ds.getChild(i);
+        if (sn.getType().equals(
+            ConfluenceConfiguration.Specification.SPACES))
+          ds.removeChild(i);
+        else
+          i++;
+      }
+
+      SpecificationNode spaces = new SpecificationNode(
+          ConfluenceConfiguration.Specification.SPACES);
+      ds.addChild(ds.getChildCount(), spaces);
+      int spacesCount = Integer.parseInt(xc);
+      i = 0;
+      while (i < spacesCount) {
+        String spaceDescription = "_" + Integer.toString(i);
+        String spaceOpName = seqPrefix + "spaceop" + spaceDescription;
+        xc = variableContext.getParameter(spaceOpName);
+        if (xc != null && xc.equals("Delete")) {
+          // Next row
+          i++;
+          continue;
+        }
+        // Get the stuff we need
+        String spaceKey = variableContext.getParameter(seqPrefix
+            + "space" + spaceDescription);
+        SpecificationNode node = new SpecificationNode(
+            ConfluenceConfiguration.Specification.SPACE);
+        node.setAttribute(
+            ConfluenceConfiguration.Specification.SPACE_KEY_ATTRIBUTE,
+            spaceKey);
+        spaces.addChild(spaces.getChildCount(), node);
+        i++;
+      }
+
+      String op = variableContext.getParameter(seqPrefix + "spaceop");
+      if (op != null && op.equals("Add")) {
+        String spaceSpec = variableContext.getParameter(seqPrefix
+            + "space");
+        SpecificationNode node = new SpecificationNode(
+            ConfluenceConfiguration.Specification.SPACE);
+        node.setAttribute(
+            ConfluenceConfiguration.Specification.SPACE_KEY_ATTRIBUTE,
+            spaceSpec);
+        spaces.addChild(spaces.getChildCount(), node);
+      }
+    }
+
+    /* Delete pages configuration */
+    int i = 0;
+    while (i < ds.getChildCount()) {
+      SpecificationNode sn = ds.getChild(i);
+      if (sn.getType()
+          .equals(ConfluenceConfiguration.Specification.PAGES))
+        ds.removeChild(i);
+      else
+        i++;
+    }
+
+    SpecificationNode pages = new SpecificationNode(
+        ConfluenceConfiguration.Specification.PAGES);
+    ds.addChild(ds.getChildCount(), pages);
+
+    String procAttachments = variableContext
+        .getParameter(seqPrefix
+            + 
ConfluenceConfiguration.Specification.PROCESS_ATTACHMENTS_ATTRIBUTE_KEY);
+    if (procAttachments != null && !procAttachments.isEmpty()) {
+      pages.setAttribute(
+          
ConfluenceConfiguration.Specification.PROCESS_ATTACHMENTS_ATTRIBUTE_KEY,
+          String.valueOf(procAttachments));
+    }
+
+    return null;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector#
+   * outputSpecificationBody
+   * (org.apache.manifoldcf.core.interfaces.IHTTPOutput, java.util.Locale,
+   * org.apache.manifoldcf.crawler.interfaces.DocumentSpecification,
+   * java.lang.String)
+   */
+  @Override
+  public void outputSpecificationBody(IHTTPOutput out, Locale locale,
+      Specification ds, int connectionSequenceNumber,
+      int actualSequenceNumber, String tabName)
+      throws ManifoldCFException, IOException {
+
+    // Output JIRAQuery tab
+    Map<String, Object> paramMap = new HashMap<String, Object>();
+    paramMap.put("TabName", tabName);
+    paramMap.put("SeqNum", Integer.toString(connectionSequenceNumber));
+    paramMap.put("SelectedNum", Integer.toString(actualSequenceNumber));
+
+    ConfluenceSpecification cs = ConfluenceSpecification.from(ds);
+
+    fillInConfSpacesSpecificationMap(paramMap, cs);
+    fillInConfPagesSpecificationMap(paramMap, cs);
+    Messages.outputResourceWithVelocity(out, locale,
+        EDIT_SPEC_FORWARD_SPACES, paramMap);
+
+    Messages.outputResourceWithVelocity(out, locale,
+        EDIT_SPEC_FORWARD_CONF_PAGES, paramMap);
+  }
+
+  /*
+   * Header for the specification
+   * 
+   * @see org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector#
+   * outputSpecificationHeader
+   * (org.apache.manifoldcf.core.interfaces.IHTTPOutput, java.util.Locale,
+   * org.apache.manifoldcf.crawler.interfaces.DocumentSpecification,
+   * java.util.List)
+   */
+  @Override
+  public void outputSpecificationHeader(IHTTPOutput out, Locale locale,
+      Specification ds, int connectionSequenceNumber,
+      List<String> tabsArray) throws ManifoldCFException, IOException {
+
+    tabsArray.add(Messages.getString(locale, CONF_SPACES_TAB_PROPERTY));
+    tabsArray.add(Messages.getString(locale, CONF_PAGES_TAB_PROPERTY));
+
+    Map<String, Object> paramMap = new HashMap<String, Object>();
+    paramMap.put("SeqNum", Integer.toString(connectionSequenceNumber));
+
+    Messages.outputResourceWithVelocity(out, locale,
+        EDIT_SPEC_HEADER_FORWARD, paramMap);
+  }
+
+  /*
+   * Adding seed documents
+   * 
+   * @see org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector#
+   * addSeedDocuments
+   * (org.apache.manifoldcf.crawler.interfaces.ISeedingActivity,
+   * org.apache.manifoldcf.crawler.interfaces.DocumentSpecification, long,
+   * long, int)
+   */
+  public String addSeedDocuments(ISeedingActivity activities,
+      Specification spec, String lastSeedVersion, long seedTime,
+      int jobMode) throws ManifoldCFException, ServiceInterruption {
+
+    if (!isConnected()) {
+      initConfluenceClient();
+    }
+
+    try {
+
+      /*
+       * Not uses delta seeding because Confluence can't be queried using
+       * dates or in a ordered way, only start and limit which can cause
+       * problems if an already indexed document is deleted, because we
+       * will miss some to-be indexed docs due to the last start parameter
+       * stored in the last execution
+       */
+      // if(lastSeedVersion != null && !lastSeedVersion.isEmpty()) {
+      // StringTokenizer tokenizer = new
+      // StringTokenizer(lastSeedVersion,"|");
+      //
+      // lastStart = new Long(lastSeedVersion);
+      // }
+
+      ConfluenceSpecification confluenceSpecification = ConfluenceSpecification
+          .from(spec);
+      List<String> spaceKeys = confluenceSpecification.getSpaces();
+
+      if (spaceKeys.isEmpty()) {
+        logger.info("No spaces configured. Processing all spaces");
+        addSeedDocumentsForSpace(Optional.<String> absent(),
+            activities, confluenceSpecification, lastSeedVersion,
+            seedTime, jobMode);
+      } else {
+        for (String space : spaceKeys) {
+          logger.info("Processing configured space {}", space);
+          addSeedDocumentsForSpace(Optional.<String> of(space),
+              activities, confluenceSpecification,
+              lastSeedVersion, seedTime, jobMode);
+        }
+      }
+
+      return "";
+    } catch (Exception e) {
+      handleConfluenceDownException(e, "seeding");
+      return null;
+    }
+  }
+
+  /**
+   * <p>
+   * Add seed documents for a given optional space
+   * </p>
+   * 
+   * @throws ServiceInterruption
+   * @throws ManifoldCFException
+   */
+  private void addSeedDocumentsForSpace(Optional<String> space,
+      ISeedingActivity activities,
+      ConfluenceSpecification confluenceSpec, String lastSeedVersion,
+      long seedTime, int jobMode) throws ManifoldCFException,
+      ServiceInterruption {
+
+    long lastStart = 0;
+    long defaultSize = 50;
+
+    if (Logging.connectors != null && Logging.connectors.isDebugEnabled()) {
+      String spaceDesc = space.isPresent() ? "space with key "
+          + space.get() : "all the spaces";
+      Logging.connectors.debug(MessageFormat.format(
+          "Starting from {0} and size {1} for {2}", new Object[] {
+              lastStart, defaultSize, spaceDesc }));
+    }
+
+    try {
+      Boolean isLast = true;
+      do {
+        final ConfluenceResponse<Page> response = confluenceClient.getPages(
+            (int) lastStart, (int) defaultSize, space);
+
+        int count = 0;
+        for (Page page : response.getResults()) {
+
+          activities.addSeedDocument(page.getId());
+          if (confluenceSpec.isProcessAttachments()) {
+            processSeedAttachments(page, activities);
+          }
+          count++;
+        }
+        if (Logging.connectors != null
+            && Logging.connectors.isDebugEnabled())
+          Logging.connectors.debug(MessageFormat.format(
+              "Fetched and added {0} seed documents",
+              new Object[] { new Integer(count) }));
+
+        lastStart += count;
+        isLast = response.isLast();
+        if (Logging.connectors != null
+            && Logging.connectors.isDebugEnabled())
+          Logging.connectors.debug(MessageFormat.format(
+              "New start {0} and size {1}", new Object[] {
+                  lastStart, defaultSize }));
+      } while (!isLast);
+
+    } catch (Exception e) {
+      handleConfluenceDownException(e, "seeding");
+    }
+
+  }
+
+  /**
+   * <p>
+   * Process seed attachments for the given page
+   * </p>
+   * 
+   * @param page
+   * @param activities
+   */
+  private void processSeedAttachments(Page page, ISeedingActivity activities)
+      throws ManifoldCFException, ServiceInterruption {
+    long lastStart = 0;
+    long defaultSize = 50;
+
+    if (Logging.connectors != null && Logging.connectors.isDebugEnabled()) {
+      Logging.connectors
+          .debug(MessageFormat
+              .format("Processing page {} attachments starting from {} and 
size {}",
+                  new Object[] { page.getId(), lastStart,
+                      defaultSize }));
+    }
+
+    try {
+      Boolean isLast = true;
+      do {
+        final ConfluenceResponse<Attachment> response = confluenceClient
+            .getPageAttachments(page.getId(), (int) lastStart,
+                (int) defaultSize);
+
+        int count = 0;
+        for (Page resultPage : response.getResults()) {
+          activities.addSeedDocument(ConfluenceUtil
+              .generateRepositoryDocumentIdentifier(
+                  resultPage.getId(), page.getId()));
+          count++;
+        }
+
+        if (Logging.connectors != null
+            && Logging.connectors.isDebugEnabled())
+          Logging.connectors
+              .debug(MessageFormat
+                  .format("Fetched and added {} seed document attachments for 
page {}",
+                      new Object[] { new Integer(count),
+                          page.getId() }));
+
+        lastStart += count;
+        isLast = response.isLast();
+        if (Logging.connectors != null
+            && Logging.connectors.isDebugEnabled())
+          Logging.connectors.debug(MessageFormat.format(
+              "New start {0} and size {1}", new Object[] {
+                  lastStart, defaultSize }));
+      } while (!isLast);
+
+    } catch (Exception e) {
+      handleConfluenceDownException(e, "seeding");
+    }
+  }
+
+  protected static void handleConfluenceDownException(Exception e,
+      String context) throws ManifoldCFException, ServiceInterruption {
+    long currentTime = System.currentTimeMillis();
+
+    // Server doesn't appear to by up. Try for a brief time then give up.
+    String message = "Server appears down during " + context + ": "
+        + e.getMessage();
+    Logging.connectors.warn(message, e);
+    throw new ServiceInterruption(message, e, currentTime
+        + interruptionRetryTime, -1L, 3, true);
+  }
+
+  /*
+   * Process documents
+   * 
+   * @see org.apache.manifoldcf.crawler.connectors.BaseRepositoryConnector#
+   * processDocuments(java.lang.String[], java.lang.String[],
+   * org.apache.manifoldcf.crawler.interfaces.IProcessActivity,
+   * org.apache.manifoldcf.crawler.interfaces.DocumentSpecification,
+   * boolean[])
+   */
+  @Override
+  public void processDocuments(String[] documentIdentifiers,
+      IExistingVersions statuses, Specification spec,
+      IProcessActivity activities, int jobMode,
+      boolean usesDefaultAuthority) throws ManifoldCFException,
+      ServiceInterruption {
+
+    if(Logging.connectors != null && Logging.connectors.isDebugEnabled())
+      Logging.connectors
+        .debug("Process Confluence documents: Inside processDocuments");
+
+    for (int i = 0; i < documentIdentifiers.length; i++) {
+      String pageId = documentIdentifiers[i];
+      String version = statuses.getIndexedVersionString(pageId);
+
+      long startTime = System.currentTimeMillis();
+      String errorCode = "OK";
+      String errorDesc = StringUtils.EMPTY;
+      ProcessResult pResult = null;
+      boolean doLog = true;
+
+      try {
+        if (Logging.connectors != null && Logging.connectors.isDebugEnabled()) 
{
+          Logging.connectors
+              .debug("Confluence: Processing document identifier '"
+                  + pageId + "'");
+        }
+
+        /* Ensure Confluence client is connected */
+        if (!isConnected()) {
+          initConfluenceClient();
+        }
+
+        if (ConfluenceUtil.isAttachment(pageId)) {
+          pResult = processPageAsAttachment(pageId, version,
+              activities, doLog);
+        }
+        else {
+          pResult = processPage(pageId, version, activities, doLog,
+              Maps.<String, String> newHashMap());
+        }
+      } catch (IOException ioe) {
+        handleIOException(ioe);
+      } catch (Exception e) {
+        handleException(e);
+      }
+
+      finally {
+        if (doLog){
+          if(pResult.errorCode != null && !pResult.errorCode.isEmpty()){
+            activities.recordActivity(new Long(startTime),
+                ACTIVITY_READ, pResult.fileSize, pageId, pResult.errorCode,
+                  pResult.errorDescription, null);
+          }else{
+            activities.recordActivity(new Long(startTime),
+                ACTIVITY_READ, pResult.fileSize, pageId, errorCode,
+                  errorDesc, null);
+          }
+        }
+      }
+
+    }
+  }
+
+  /**
+   * <p>
+   * Process the specific page
+   * </p>
+   * 
+   * @param pageId
+   *            The pageId being an attachment
+   * @param version
+   *            The version of the page
+   * @param activities
+   * @param doLog
+   * @throws ManifoldCFException
+   * @throws IOException
+   * @throws ServiceInterruption
+   */
+  private ProcessResult processPage(String pageId, String version,
+      IProcessActivity activities, boolean doLog,
+      Map<String, String> extraProperties) throws ManifoldCFException,
+      ServiceInterruption, IOException {
+    Page page = confluenceClient.getPage(pageId);
+    return processPageInternal(page, pageId, version, activities, doLog,
+        extraProperties);
+  }
+
+  /**
+   * <p>
+   * Process the specific attachment
+   * </p>
+   * 
+   * @param pageId
+   *            The pageId being an attachment
+   * @param version
+   *            The version of the page
+   * @param activities
+   * @param doLog
+   * @throws IOException
+   * @throws ServiceInterruption
+   */
+  private ProcessResult processPageAsAttachment(String pageId, String version,
+      IProcessActivity activities, boolean doLog)
+      throws ManifoldCFException, ServiceInterruption, IOException {
+
+    String[] ids = ConfluenceUtil.getAttachmentAndPageId(pageId);
+    Attachment attachment = confluenceClient.getAttachment(ids[0]);
+    Map<String, String> extraProperties = Maps.newHashMap();
+    extraProperties.put("attachedBy", ids[1]);
+    return processPageInternal(attachment, pageId, version, activities, doLog,
+        extraProperties);
+  }
+
+  /**
+   * <p>
+   * Process the specific page
+   * </p>
+   * 
+   * @param pageId
+   *            The pageId being an attachment
+   * @param manifoldDocumentIdentifier
+   * @param version
+   *            The version of the page
+   * @param activities
+   * @param doLog
+   * @throws ManifoldCFException
+   * @throws IOException
+   * @throws ServiceInterruption
+   */
+  private ProcessResult processPageInternal(Page page,
+      String manifoldDocumentIdentifier, String version,
+      IProcessActivity activities, boolean doLog,
+      Map<String, String> extraProperties) throws ManifoldCFException,
+      ServiceInterruption, IOException {
+
+        
+    /* Remove page if it has no content */
+    /*
+     * Page does not have content if there was an error trying to get the
+     * page
+     */
+    if (!page.hasContent()) {
+      activities.deleteDocument(manifoldDocumentIdentifier);
+      return new ProcessResult(page.getLength(), "DELETED", "");
+    }
+    if (Logging.connectors != null && Logging.connectors.isDebugEnabled()) {
+      Logging.connectors.debug("Confluence: This content exists: "
+          + page.getId());
+    }
+
+    RepositoryDocument rd = new RepositoryDocument();
+    Date createdDate = page.getCreatedDate();
+    Date lastModified = page.getLastModifiedDate();
+    DateFormat df = DateFormat.getDateTimeInstance();
+
+    /*
+     * Retain page in Manifold because it has not changed from last time
+     * This is needed to keep the identifier in Manifold data, because by
+     * default if a document is not retained nor ingested, it will be
+     * deleted by the framework
+     */
+    String lastVersion = df.format(lastModified);
+    
+    if (!activities.checkDocumentNeedsReindexing(manifoldDocumentIdentifier, 
lastVersion)) {
+      return new ProcessResult(page.getLength(), "RETAINED", "");
+    }
+    
+    if (!activities.checkLengthIndexable(page.getLength())){
+      activities.noDocument(page.getId(), lastVersion);
+      String errorCode = IProcessActivity.EXCLUDED_LENGTH;
+      String errorDesc = "Excluding document because of length 
("+page.getLength()+")";
+      return new ProcessResult(page.getLength(), errorCode, errorDesc);
+    }
+
+    if (!activities.checkMimeTypeIndexable(page.getMediaType())) {
+      activities.noDocument(page.getId(), lastVersion);
+      String errorCode = IProcessActivity.EXCLUDED_MIMETYPE;
+      String errorDesc = "Excluding document because of mime type 
("+page.getMediaType()+")";
+      return new ProcessResult(page.getLength(), errorCode, errorDesc);
+    }
+
+    if (!activities.checkDateIndexable(lastModified)) {
+      activities.noDocument(page.getId(), lastVersion);
+      String errorCode = IProcessActivity.EXCLUDED_DATE;
+      String errorDesc = "Excluding document because of date 
("+lastModified+")";
+      return new ProcessResult(page.getLength(), errorCode, errorDesc);
+    }
+
+    if (!activities.checkURLIndexable(page.getWebUrl())) {
+      activities.noDocument(page.getId(), lastVersion);
+      String errorCode = IProcessActivity.EXCLUDED_URL;
+      String errorDesc = "Excluding document because of URL 
('"+page.getWebUrl()+"')";
+      return new ProcessResult(page.getLength(), errorCode, errorDesc);
+    }
+
+    /* Add repository document information */
+    rd.setMimeType(page.getMediaType());
+    if (createdDate != null)
+      rd.setCreatedDate(createdDate);
+    if (lastModified != null)
+      rd.setModifiedDate(lastModified);
+    rd.setIndexingDate(new Date());
+
+    /* Adding Page Metadata */
+    Map<String, Object> pageMetadata = page.getMetadataAsMap();
+    for (Entry<String, Object> entry : pageMetadata.entrySet()) {
+      if(entry.getValue() instanceof List) {
+        List<?> list = (List<?>)entry.getValue();
+        rd.addField(entry.getKey(), list.toArray(new String[list.size()]));
+      }
+      else {
+        rd.addField(entry.getKey(), entry.getValue().toString());
+      }
+    }
+
+    /* Adding extra properties */
+    for (Entry<String, String> entry : extraProperties.entrySet()) {
+      rd.addField(entry.getKey(), entry.getValue());
+    }
+
+    String documentURI = page.getWebUrl();
+
+    /* Set repository document ACLs */
+    rd.setSecurityACL(RepositoryDocument.SECURITY_TYPE_DOCUMENT,
+        new String[] { page.getSpace() });
+    rd.setSecurityDenyACL(RepositoryDocument.SECURITY_TYPE_DOCUMENT,
+        new String[] { defaultAuthorityDenyToken });
+
+    rd.setBinary(page.getContentStream(), page.getLength());
+    rd.addField("size", String.valueOf(page.getLength()));
+
+    /* Ingest document */
+    activities.ingestDocumentWithException(manifoldDocumentIdentifier,
+        lastVersion, documentURI, rd);
+    
+    return new ProcessResult(page.getLength(), null, null);
+  }
+
+  /**
+   * <p>
+   * Handles IO Exception to manage whether the exception is an interruption
+   * so that the process needs to be executed again later on
+   * </p>
+   * 
+   * @param e
+   *            The Exception
+   * @throws ManifoldCFException
+   * @throws ServiceInterruption
+   */
+  private static void handleIOException(IOException e)
+      throws ManifoldCFException, ServiceInterruption {
+    if (!(e instanceof java.net.SocketTimeoutException)
+        && (e instanceof InterruptedIOException)) {
+      throw new ManifoldCFException("Interrupted: " + e.getMessage(), e,
+          ManifoldCFException.INTERRUPTED);
+    }
+    Logging.connectors.warn("IO exception: " + e.getMessage(), e);
+    long currentTime = System.currentTimeMillis();
+    throw new ServiceInterruption("IO exception: " + e.getMessage(), e,
+        currentTime + 300000L, currentTime + 3 * 60 * 60000L, -1, false);
+  }
+
+  /**
+   * <p>
+   * Handles general exceptions
+   * </p>
+   * 
+   * @param e
+   *            The Exception
+   * @throws ManifoldCFException
+   */
+  private static void handleException(Exception e) throws ManifoldCFException {
+    Logging.connectors.warn("Exception: " + e.getMessage(), e);
+    throw new ManifoldCFException("Exception: " + e.getMessage(), e,
+        ManifoldCFException.REPOSITORY_CONNECTION_ERROR);
+
+  }
+  
+  private class ProcessResult{
+    private long fileSize;
+    private String errorCode;
+    private String errorDescription;
+    
+    private ProcessResult(long fileSize, String errorCode, String 
errorDescription){
+      this.fileSize = fileSize;
+      this.errorCode = errorCode;
+      this.errorDescription = errorDescription;
+    }
+  }
+
+  /**
+   * <p>
+   * Internal private class used to parse and keep the specification
+   * configuration in object format
+   * </p>
+   * 
+   * @author Antonio David Perez Morales <[email protected]>
+   *
+   */
+  private static class ConfluenceSpecification {
+    private List<String> spaces;
+    private Boolean processAttachments = false;
+
+    /**
+     * <p>
+     * Returns if attachments should be processed
+     * </p>
+     * 
+     * @return a {@code Boolean} indicating if the attachments should be
+     *         processed or not
+     */
+    public Boolean isProcessAttachments() {
+      return this.processAttachments;
+    }
+
+    /**
+     * <p>
+     * Returns the list of configured spaces or an empty list meaning that
+     * all spaces should be processed
+     * </p>
+     * 
+     * @return a {@code List<String>} of configured spaces
+     */
+    public List<String> getSpaces() {
+      return this.spaces;
+    }
+
+    public static ConfluenceSpecification from(Specification spec) {
+      ConfluenceSpecification cs = new ConfluenceSpecification();
+      cs.spaces = Lists.newArrayList();
+      for (int i = 0, len = spec.getChildCount(); i < len; i++) {
+        SpecificationNode sn = spec.getChild(i);
+        if (sn.getType().equals(
+            ConfluenceConfiguration.Specification.SPACES)) {
+          for (int j = 0, sLen = sn.getChildCount(); j < sLen; j++) {
+            SpecificationNode specNode = sn.getChild(j);
+            if (specNode.getType().equals(
+                ConfluenceConfiguration.Specification.SPACE)) {
+              cs.spaces
+                  .add(specNode
+                      
.getAttributeValue(ConfluenceConfiguration.Specification.SPACE_KEY_ATTRIBUTE));
+
+            }
+          }
+
+        } else if (sn.getType().equals(
+            ConfluenceConfiguration.Specification.PAGES)) {
+          String s = sn
+              
.getAttributeValue(ConfluenceConfiguration.Specification.PROCESS_ATTACHMENTS_ATTRIBUTE_KEY);
+          cs.processAttachments = Boolean.valueOf(s);
+        }
+      }
 
-                       return cs;
+      return cs;
 
-               }
-       }
+    }
+  }
 
 }


Reply via email to