blob: ea8de4c268b8285f34afe0a6b0363311108d1222 [file] [log] [blame]
/* $Id: ManifoldCF.java 996524 2010-09-13 13:38:01Z kwright $ */
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.manifoldcf.crawler.system;
import org.apache.manifoldcf.core.interfaces.*;
import org.apache.manifoldcf.agents.interfaces.*;
import org.apache.manifoldcf.crawler.interfaces.*;
import org.apache.manifoldcf.authorities.interfaces.*;
import java.io.*;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.*;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class ManifoldCF extends org.apache.manifoldcf.agents.system.ManifoldCF
{
public static final String _rcsid = "@(#)$Id: ManifoldCF.java 996524 2010-09-13 13:38:01Z kwright $";
// Initialization flag.
protected static boolean crawlerInitialized = false;
// Thread objects.
// These get filled in as threads are created.
protected static InitializationThread initializationThread = null;
protected static JobStartThread jobStartThread = null;
protected static StufferThread stufferThread = null;
protected static FinisherThread finisherThread = null;
protected static JobNotificationThread notificationThread = null;
protected static StartupThread startupThread = null;
protected static StartDeleteThread startDeleteThread = null;
protected static JobDeleteThread jobDeleteThread = null;
protected static WorkerThread[] workerThreads = null;
protected static ExpireStufferThread expireStufferThread = null;
protected static ExpireThread[] expireThreads = null;
protected static DocumentDeleteStufferThread deleteStufferThread = null;
protected static DocumentDeleteThread[] deleteThreads = null;
protected static DocumentCleanupStufferThread cleanupStufferThread = null;
protected static DocumentCleanupThread[] cleanupThreads = null;
protected static JobResetThread jobResetThread = null;
protected static SeedingThread seedingThread = null;
protected static IdleCleanupThread idleCleanupThread = null;
protected static SetPriorityThread setPriorityThread = null;
// Reset managers
/** Worker thread pool reset manager */
protected static WorkerResetManager workerResetManager = null;
/** Delete thread pool reset manager */
protected static DocDeleteResetManager docDeleteResetManager = null;
/** Cleanup thread pool reset manager */
protected static DocCleanupResetManager docCleanupResetManager = null;
// Number of worker threads
protected static int numWorkerThreads = 0;
// Number of delete threads
protected static int numDeleteThreads = 0;
// Number of cleanup threads
protected static int numCleanupThreads = 0;
// Number of expiration threads
protected static int numExpireThreads = 0;
// Factor for low water level in queueing
protected static float lowWaterFactor = 5.0f;
// Factor in amount to stuff
protected static float stuffAmtFactor = 0.5f;
// Properties
protected static final String workerThreadCountProperty = "org.apache.manifoldcf.crawler.threads";
protected static final String deleteThreadCountProperty = "org.apache.manifoldcf.crawler.deletethreads";
protected static final String cleanupThreadCountProperty = "org.apache.manifoldcf.crawler.cleanupthreads";
protected static final String expireThreadCountProperty = "org.apache.manifoldcf.crawler.expirethreads";
protected static final String lowWaterFactorProperty = "org.apache.manifoldcf.crawler.lowwaterfactor";
protected static final String stuffAmtFactorProperty = "org.apache.manifoldcf.crawler.stuffamountfactor";
protected static final String connectorsConfigurationFileProperty = "org.apache.manifoldcf.connectorsconfigurationfile";
protected static final String databaseSuperuserNameProperty = "org.apache.manifoldcf.dbsuperusername";
protected static final String databaseSuperuserPasswordProperty = "org.apache.manifoldcf.dbsuperuserpassword";
protected static final String salt = "org.apache.manifoldcf.salt";
/** This object is used to make sure the initialization sequence is atomic. Shutdown cannot occur until the system is in a known state. */
protected static Integer startupLock = new Integer(0);
/** Initialize environment.
*/
public static void initializeEnvironment()
throws ManifoldCFException
{
synchronized (initializeFlagLock)
{
org.apache.manifoldcf.agents.system.ManifoldCF.initializeEnvironment();
org.apache.manifoldcf.authorities.system.ManifoldCF.localInitialize();
org.apache.manifoldcf.crawler.system.ManifoldCF.localInitialize();
}
}
public static void cleanUpEnvironment()
{
synchronized (initializeFlagLock)
{
org.apache.manifoldcf.authorities.system.ManifoldCF.localCleanup();
org.apache.manifoldcf.crawler.system.ManifoldCF.localCleanup();
org.apache.manifoldcf.agents.system.ManifoldCF.cleanUpEnvironment();
}
}
public static void localInitialize()
throws ManifoldCFException
{
synchronized (initializeFlagLock)
{
if (crawlerInitialized)
return;
Logging.initializeLoggers();
Logging.setLogLevels();
crawlerInitialized = true;
}
}
public static void localCleanup()
{
}
/** Create system database using superuser properties from properties.xml.
*/
public static void createSystemDatabase(IThreadContext threadContext)
throws ManifoldCFException
{
// Get the specified superuser name and password, in case this isn't Derby we're using
String superuserName = getProperty(databaseSuperuserNameProperty);
if (superuserName == null)
superuserName = "";
String superuserPassword = getProperty(databaseSuperuserPasswordProperty);
if (superuserPassword == null)
superuserPassword = "";
createSystemDatabase(threadContext,superuserName,superuserPassword);
}
/** Register this agent */
public static void registerThisAgent(IThreadContext tc)
throws ManifoldCFException
{
// Register
IAgentManager agentMgr = AgentManagerFactory.make(tc);
agentMgr.registerAgent("org.apache.manifoldcf.crawler.system.CrawlerAgent");
}
/** Register or re-register all connectors, based on a connectors.xml file.
*/
public static void reregisterAllConnectors(IThreadContext tc)
throws ManifoldCFException
{
// Read connectors configuration file (to figure out what we need to register)
File connectorConfigFile = getFileProperty(connectorsConfigurationFileProperty);
Connectors c = readConnectorDeclarations(connectorConfigFile);
// Unregister all the connectors we don't want.
unregisterAllConnectors(tc,c);
// Register (or update) all connectors specified by connectors.xml
registerConnectors(tc,c);
}
/** Read connectors configuration file.
*/
public static Connectors readConnectorDeclarations(File connectorConfigFile)
throws ManifoldCFException
{
Connectors c = null;
if (connectorConfigFile != null)
{
try
{
// Open the file, read it, and attempt to do the connector registrations
InputStream is = new FileInputStream(connectorConfigFile);
try
{
c = new Connectors(is);
}
finally
{
is.close();
}
}
catch (FileNotFoundException e)
{
throw new ManifoldCFException("Couldn't find connector configuration file: "+e.getMessage(),e);
}
catch (IOException e)
{
throw new ManifoldCFException("Error reading connector configuration file: "+e.getMessage(),e);
}
}
return c;
}
/** Unregister all connectors.
*/
public static void unregisterAllConnectors(IThreadContext tc)
throws ManifoldCFException
{
unregisterAllConnectors(tc,null);
}
// Connectors configuration file
protected static final String NODE_OUTPUTCONNECTOR = "outputconnector";
protected static final String NODE_MAPPINGCONNECTOR = "mappingconnector";
protected static final String NODE_AUTHORITYCONNECTOR = "authorityconnector";
protected static final String NODE_REPOSITORYCONNECTOR = "repositoryconnector";
protected static final String ATTRIBUTE_NAME = "name";
protected static final String ATTRIBUTE_CLASS = "class";
/** Unregister all connectors which don't match a specified connector list.
*/
public static void unregisterAllConnectors(IThreadContext tc, Connectors c)
throws ManifoldCFException
{
// Create a map of class name and description, so we can compare what we can find
// against what we want.
Map<String,String> desiredOutputConnectors = new HashMap<String,String>();
Map<String,String> desiredMappingConnectors = new HashMap<String,String>();
Map<String,String> desiredAuthorityConnectors = new HashMap<String,String>();
Map<String,String> desiredRepositoryConnectors = new HashMap<String,String>();
if (c != null)
{
for (int i = 0; i < c.getChildCount(); i++)
{
ConfigurationNode cn = c.findChild(i);
if (cn.getType().equals(NODE_OUTPUTCONNECTOR))
{
String name = cn.getAttributeValue(ATTRIBUTE_NAME);
String className = cn.getAttributeValue(ATTRIBUTE_CLASS);
desiredOutputConnectors.put(className,name);
}
else if (cn.getType().equals(NODE_MAPPINGCONNECTOR))
{
String name = cn.getAttributeValue(ATTRIBUTE_NAME);
String className = cn.getAttributeValue(ATTRIBUTE_CLASS);
desiredMappingConnectors.put(className,name);
}
else if (cn.getType().equals(NODE_AUTHORITYCONNECTOR))
{
String name = cn.getAttributeValue(ATTRIBUTE_NAME);
String className = cn.getAttributeValue(ATTRIBUTE_CLASS);
desiredAuthorityConnectors.put(className,name);
}
else if (cn.getType().equals(NODE_REPOSITORYCONNECTOR))
{
String name = cn.getAttributeValue(ATTRIBUTE_NAME);
String className = cn.getAttributeValue(ATTRIBUTE_CLASS);
desiredRepositoryConnectors.put(className,name);
}
}
}
// Grab a database handle, so we can use transactions later.
IDBInterface database = DBInterfaceFactory.make(tc,
ManifoldCF.getMasterDatabaseName(),
ManifoldCF.getMasterDatabaseUsername(),
ManifoldCF.getMasterDatabasePassword());
// Output connectors...
{
IOutputConnectorManager mgr = OutputConnectorManagerFactory.make(tc);
IOutputConnectionManager connManager = OutputConnectionManagerFactory.make(tc);
IResultSet classNames = mgr.getConnectors();
int i = 0;
while (i < classNames.getRowCount())
{
IResultRow row = classNames.getRow(i++);
String className = (String)row.getValue("classname");
String description = (String)row.getValue("description");
if (desiredOutputConnectors.get(className) == null || !desiredOutputConnectors.get(className).equals(description))
{
// Deregistration should be done in a transaction
database.beginTransaction();
try
{
// Find the connection names that come with this class
String[] connectionNames = connManager.findConnectionsForConnector(className);
// For all connection names, notify all agents of the deregistration
AgentManagerFactory.noteOutputConnectorDeregistration(tc,connectionNames);
// Now that all jobs have been placed into an appropriate state, actually do the deregistration itself.
mgr.unregisterConnector(className);
}
catch (ManifoldCFException e)
{
database.signalRollback();
throw e;
}
catch (Error e)
{
database.signalRollback();
throw e;
}
finally
{
database.endTransaction();
}
}
}
System.err.println("Successfully unregistered all output connectors");
}
// Mapping connectors...
{
IMappingConnectorManager mgr = MappingConnectorManagerFactory.make(tc);
IResultSet classNames = mgr.getConnectors();
int i = 0;
while (i < classNames.getRowCount())
{
IResultRow row = classNames.getRow(i++);
String className = (String)row.getValue("classname");
String description = (String)row.getValue("description");
if (desiredMappingConnectors.get(className) == null || !desiredMappingConnectors.get(className).equals(description))
{
mgr.unregisterConnector(className);
}
}
System.err.println("Successfully unregistered all mapping connectors");
}
// Authority connectors...
{
IAuthorityConnectorManager mgr = AuthorityConnectorManagerFactory.make(tc);
IResultSet classNames = mgr.getConnectors();
int i = 0;
while (i < classNames.getRowCount())
{
IResultRow row = classNames.getRow(i++);
String className = (String)row.getValue("classname");
String description = (String)row.getValue("description");
if (desiredAuthorityConnectors.get(className) == null || !desiredAuthorityConnectors.get(className).equals(description))
{
mgr.unregisterConnector(className);
}
}
System.err.println("Successfully unregistered all authority connectors");
}
// Repository connectors...
{
IConnectorManager mgr = ConnectorManagerFactory.make(tc);
IJobManager jobManager = JobManagerFactory.make(tc);
IRepositoryConnectionManager connManager = RepositoryConnectionManagerFactory.make(tc);
IResultSet classNames = mgr.getConnectors();
int i = 0;
while (i < classNames.getRowCount())
{
IResultRow row = classNames.getRow(i++);
String className = (String)row.getValue("classname");
String description = (String)row.getValue("description");
if (desiredRepositoryConnectors.get(className) == null || !desiredRepositoryConnectors.get(className).equals(description))
{
// Deregistration should be done in a transaction
database.beginTransaction();
try
{
// Find the connection names that come with this class
String[] connectionNames = connManager.findConnectionsForConnector(className);
// For each connection name, modify the jobs to note that the connector is no longer installed
jobManager.noteConnectorDeregistration(connectionNames);
// Now that all jobs have been placed into an appropriate state, actually do the deregistration itself.
mgr.unregisterConnector(className);
}
catch (ManifoldCFException e)
{
database.signalRollback();
throw e;
}
catch (Error e)
{
database.signalRollback();
throw e;
}
finally
{
database.endTransaction();
}
}
}
System.err.println("Successfully unregistered all repository connectors");
}
}
/** Register all connectors as specified by a Connectors structure, usually read from the connectors.xml file.
*/
public static void registerConnectors(IThreadContext tc, Connectors c)
throws ManifoldCFException
{
if (c != null)
{
// Grab a database handle, so we can use transactions later.
IDBInterface database = DBInterfaceFactory.make(tc,
ManifoldCF.getMasterDatabaseName(),
ManifoldCF.getMasterDatabaseUsername(),
ManifoldCF.getMasterDatabasePassword());
// Other code will go here to discover and register various connectors that exist in the classpath
int i = 0;
while (i < c.getChildCount())
{
ConfigurationNode cn = c.findChild(i++);
if (cn.getType().equals(NODE_OUTPUTCONNECTOR))
{
String name = cn.getAttributeValue(ATTRIBUTE_NAME);
String className = cn.getAttributeValue(ATTRIBUTE_CLASS);
IOutputConnectorManager mgr = OutputConnectorManagerFactory.make(tc);
IOutputConnectionManager connManager = OutputConnectionManagerFactory.make(tc);
// Registration should be done in a transaction
database.beginTransaction();
try
{
// First, register connector
mgr.registerConnector(name,className);
// Then, signal to all jobs that might depend on this connector that they can switch state
// Find the connection names that come with this class
String[] connectionNames = connManager.findConnectionsForConnector(className);
// For all connection names, notify all agents of the registration
AgentManagerFactory.noteOutputConnectorRegistration(tc,connectionNames);
}
catch (ManifoldCFException e)
{
database.signalRollback();
throw e;
}
catch (Error e)
{
database.signalRollback();
throw e;
}
finally
{
database.endTransaction();
}
System.err.println("Successfully registered output connector '"+className+"'");
}
else if (cn.getType().equals(NODE_AUTHORITYCONNECTOR))
{
String name = cn.getAttributeValue(ATTRIBUTE_NAME);
String className = cn.getAttributeValue(ATTRIBUTE_CLASS);
IAuthorityConnectorManager mgr = AuthorityConnectorManagerFactory.make(tc);
mgr.registerConnector(name,className);
System.err.println("Successfully registered authority connector '"+className+"'");
}
else if (cn.getType().equals(NODE_MAPPINGCONNECTOR))
{
String name = cn.getAttributeValue(ATTRIBUTE_NAME);
String className = cn.getAttributeValue(ATTRIBUTE_CLASS);
IMappingConnectorManager mgr = MappingConnectorManagerFactory.make(tc);
mgr.registerConnector(name,className);
System.err.println("Successfully registered mapping connector '"+className+"'");
}
else if (cn.getType().equals(NODE_REPOSITORYCONNECTOR))
{
String name = cn.getAttributeValue(ATTRIBUTE_NAME);
String className = cn.getAttributeValue(ATTRIBUTE_CLASS);
IConnectorManager mgr = ConnectorManagerFactory.make(tc);
IJobManager jobManager = JobManagerFactory.make(tc);
IRepositoryConnectionManager connManager = RepositoryConnectionManagerFactory.make(tc);
// Deregistration should be done in a transaction
database.beginTransaction();
try
{
// First, register connector
mgr.registerConnector(name,className);
// Then, signal to all jobs that might depend on this connector that they can switch state
// Find the connection names that come with this class
String[] connectionNames = connManager.findConnectionsForConnector(className);
// For each connection name, modify the jobs to note that the connector is now installed
jobManager.noteConnectorRegistration(connectionNames);
}
catch (ManifoldCFException e)
{
database.signalRollback();
throw e;
}
catch (Error e)
{
database.signalRollback();
throw e;
}
finally
{
database.endTransaction();
}
System.err.println("Successfully registered repository connector '"+className+"'");
}
else
throw new ManifoldCFException("Unrecognized connectors node type '"+cn.getType()+"'");
}
}
}
/** Install all the crawler system tables.
*@param threadcontext is the thread context.
*/
public static void installSystemTables(IThreadContext threadcontext)
throws ManifoldCFException
{
IConnectorManager repConnMgr = ConnectorManagerFactory.make(threadcontext);
IRepositoryConnectionManager repCon = RepositoryConnectionManagerFactory.make(threadcontext);
IJobManager jobManager = JobManagerFactory.make(threadcontext);
org.apache.manifoldcf.authorities.system.ManifoldCF.installSystemTables(threadcontext);
repConnMgr.install();
repCon.install();
jobManager.install();
}
/** Uninstall all the crawler system tables.
*@param threadcontext is the thread context.
*/
public static void deinstallSystemTables(IThreadContext threadcontext)
throws ManifoldCFException
{
ManifoldCFException se = null;
IConnectorManager repConnMgr = ConnectorManagerFactory.make(threadcontext);
IRepositoryConnectionManager repCon = RepositoryConnectionManagerFactory.make(threadcontext);
IJobManager jobManager = JobManagerFactory.make(threadcontext);
jobManager.deinstall();
repCon.deinstall();
repConnMgr.deinstall();
org.apache.manifoldcf.authorities.system.ManifoldCF.deinstallSystemTables(threadcontext);
if (se != null)
throw se;
}
/** Start everything.
*/
public static void startSystem(IThreadContext threadContext)
throws ManifoldCFException
{
Logging.root.info("Starting up pull-agent...");
synchronized (startupLock)
{
// Now, start all the threads
String maxThreads = getProperty(workerThreadCountProperty);
if (maxThreads == null)
maxThreads = "100";
numWorkerThreads = new Integer(maxThreads).intValue();
if (numWorkerThreads < 1 || numWorkerThreads > 300)
throw new ManifoldCFException("Illegal value for the number of worker threads");
String maxDeleteThreads = getProperty(deleteThreadCountProperty);
if (maxDeleteThreads == null)
maxDeleteThreads = "10";
String maxCleanupThreads = getProperty(cleanupThreadCountProperty);
if (maxCleanupThreads == null)
maxCleanupThreads = "10";
String maxExpireThreads = getProperty(expireThreadCountProperty);
if (maxExpireThreads == null)
maxExpireThreads = "10";
numDeleteThreads = new Integer(maxDeleteThreads).intValue();
if (numDeleteThreads < 1 || numDeleteThreads > 300)
throw new ManifoldCFException("Illegal value for the number of delete threads");
numCleanupThreads = new Integer(maxCleanupThreads).intValue();
if (numCleanupThreads < 1 || numCleanupThreads > 300)
throw new ManifoldCFException("Illegal value for the number of cleanup threads");
numExpireThreads = new Integer(maxExpireThreads).intValue();
if (numExpireThreads < 1 || numExpireThreads > 300)
throw new ManifoldCFException("Illegal value for the number of expire threads");
String lowWaterFactorString = getProperty(lowWaterFactorProperty);
if (lowWaterFactorString == null)
lowWaterFactorString = "5";
lowWaterFactor = new Float(lowWaterFactorString).floatValue();
if (lowWaterFactor < 1.0 || lowWaterFactor > 1000.0)
throw new ManifoldCFException("Illegal value for the low water factor");
String stuffAmtFactorString = getProperty(stuffAmtFactorProperty);
if (stuffAmtFactorString == null)
stuffAmtFactorString = "2";
stuffAmtFactor = new Float(stuffAmtFactorString).floatValue();
if (stuffAmtFactor < 0.1 || stuffAmtFactor > 1000.0)
throw new ManifoldCFException("Illegal value for the stuffing amount factor");
// Create the threads and objects. This MUST be completed before there is any chance of "shutdownSystem" getting called.
QueueTracker queueTracker = new QueueTracker();
DocumentQueue documentQueue = new DocumentQueue();
DocumentDeleteQueue documentDeleteQueue = new DocumentDeleteQueue();
DocumentCleanupQueue documentCleanupQueue = new DocumentCleanupQueue();
DocumentCleanupQueue expireQueue = new DocumentCleanupQueue();
BlockingDocuments blockingDocuments = new BlockingDocuments();
workerResetManager = new WorkerResetManager(documentQueue,expireQueue);
docDeleteResetManager = new DocDeleteResetManager(documentDeleteQueue);
docCleanupResetManager = new DocCleanupResetManager(documentCleanupQueue);
jobStartThread = new JobStartThread();
startupThread = new StartupThread(queueTracker);
startDeleteThread = new StartDeleteThread();
finisherThread = new FinisherThread();
notificationThread = new JobNotificationThread();
jobDeleteThread = new JobDeleteThread();
stufferThread = new StufferThread(documentQueue,numWorkerThreads,workerResetManager,queueTracker,blockingDocuments,lowWaterFactor,stuffAmtFactor);
expireStufferThread = new ExpireStufferThread(expireQueue,numExpireThreads,workerResetManager);
setPriorityThread = new SetPriorityThread(queueTracker,numWorkerThreads,blockingDocuments);
workerThreads = new WorkerThread[numWorkerThreads];
int i = 0;
while (i < numWorkerThreads)
{
workerThreads[i] = new WorkerThread(Integer.toString(i),documentQueue,workerResetManager,queueTracker);
i++;
}
expireThreads = new ExpireThread[numExpireThreads];
i = 0;
while (i < numExpireThreads)
{
expireThreads[i] = new ExpireThread(Integer.toString(i),expireQueue,queueTracker,workerResetManager);
i++;
}
deleteStufferThread = new DocumentDeleteStufferThread(documentDeleteQueue,numDeleteThreads,docDeleteResetManager);
deleteThreads = new DocumentDeleteThread[numDeleteThreads];
i = 0;
while (i < numDeleteThreads)
{
deleteThreads[i] = new DocumentDeleteThread(Integer.toString(i),documentDeleteQueue,docDeleteResetManager);
i++;
}
cleanupStufferThread = new DocumentCleanupStufferThread(documentCleanupQueue,numCleanupThreads,docCleanupResetManager);
cleanupThreads = new DocumentCleanupThread[numCleanupThreads];
i = 0;
while (i < numCleanupThreads)
{
cleanupThreads[i] = new DocumentCleanupThread(Integer.toString(i),documentCleanupQueue,queueTracker,docCleanupResetManager);
i++;
}
jobResetThread = new JobResetThread(queueTracker);
seedingThread = new SeedingThread(queueTracker);
idleCleanupThread = new IdleCleanupThread();
initializationThread = new InitializationThread(queueTracker);
// Start the initialization thread. This does the initialization work and starts all the other threads when that's done. It then exits.
initializationThread.start();
}
Logging.root.info("Pull-agent started");
}
protected static class InitializationThread extends Thread
{
protected final QueueTracker queueTracker;
public InitializationThread(QueueTracker queueTracker)
{
super();
this.queueTracker = queueTracker;
setName("Initialization thread");
setDaemon(true);
}
public void run()
{
int i;
// Initialize the database
try
{
IThreadContext threadContext = ThreadContextFactory.make();
// First, get a job manager
IJobManager jobManager = JobManagerFactory.make(threadContext);
IRepositoryConnectionManager mgr = RepositoryConnectionManagerFactory.make(threadContext);
Logging.threads.debug("Agents process starting initialization...");
// Call the database to get it ready
jobManager.prepareForStart();
Logging.threads.debug("Agents process reprioritizing documents...");
HashMap connectionMap = new HashMap();
HashMap jobDescriptionMap = new HashMap();
// Reprioritize all documents in the jobqueue, 1000 at a time
long currentTime = System.currentTimeMillis();
// Do the 'not yet processed' documents only. Documents that are queued for reprocessing will be assigned
// new priorities. Already processed documents won't. This guarantees that our bins are appropriate for current thread
// activity.
// In order for this to be the correct functionality, ALL reseeding and requeuing operations MUST reset the associated document
// priorities.
while (true)
{
long startTime = System.currentTimeMillis();
DocumentDescription[] docs = jobManager.getNextNotYetProcessedReprioritizationDocuments(currentTime, 10000);
if (docs.length == 0)
break;
// Calculate new priorities for all these documents
writeDocumentPriorities(threadContext,mgr,jobManager,docs,connectionMap,jobDescriptionMap,queueTracker,currentTime);
Logging.threads.debug("Reprioritized "+Integer.toString(docs.length)+" not-yet-processed documents in "+new Long(System.currentTimeMillis()-startTime)+" ms");
}
Logging.threads.debug("Agents process initialization complete!");
// Start all the threads
jobStartThread.start();
startupThread.start();
startDeleteThread.start();
finisherThread.start();
notificationThread.start();
jobDeleteThread.start();
stufferThread.start();
expireStufferThread.start();
setPriorityThread.start();
i = 0;
while (i < numWorkerThreads)
{
workerThreads[i].start();
i++;
}
i = 0;
while (i < numExpireThreads)
{
expireThreads[i].start();
i++;
}
cleanupStufferThread.start();
i = 0;
while (i < numCleanupThreads)
{
cleanupThreads[i].start();
i++;
}
deleteStufferThread.start();
i = 0;
while (i < numDeleteThreads)
{
deleteThreads[i].start();
i++;
}
jobResetThread.start();
seedingThread.start();
idleCleanupThread.start();
// exit!
}
catch (Throwable e)
{
// Severe error on initialization
if (e instanceof ManifoldCFException)
{
// Deal with interrupted exception gracefully, because it means somebody is trying to shut us down before we got started.
if (((ManifoldCFException)e).getErrorCode() == ManifoldCFException.INTERRUPTED)
return;
}
System.err.println("agents process could not start - shutting down");
Logging.threads.fatal("Startup initialization error tossed: "+e.getMessage(),e);
System.exit(-300);
}
}
}
/** Stop the system.
*/
public static void stopSystem(IThreadContext threadContext)
throws ManifoldCFException
{
Logging.root.info("Shutting down pull-agent...");
synchronized (startupLock)
{
while (initializationThread != null || jobDeleteThread != null || startupThread != null || startDeleteThread != null ||
jobStartThread != null || stufferThread != null ||
finisherThread != null || notificationThread != null || workerThreads != null || expireStufferThread != null || expireThreads != null ||
deleteStufferThread != null || deleteThreads != null ||
cleanupStufferThread != null || cleanupThreads != null ||
jobResetThread != null || seedingThread != null || idleCleanupThread != null || setPriorityThread != null)
{
// Send an interrupt to all threads that are still there.
// In theory, this only needs to be done once. In practice, I have seen cases where the thread loses track of the fact that it has been
// interrupted (which may be a JVM bug - who knows?), but in any case there's no harm in doing it again.
if (initializationThread != null)
{
initializationThread.interrupt();
}
if (setPriorityThread != null)
{
setPriorityThread.interrupt();
}
if (jobStartThread != null)
{
jobStartThread.interrupt();
}
if (jobDeleteThread != null)
{
jobDeleteThread.interrupt();
}
if (startupThread != null)
{
startupThread.interrupt();
}
if (startDeleteThread != null)
{
startDeleteThread.interrupt();
}
if (stufferThread != null)
{
stufferThread.interrupt();
}
if (expireStufferThread != null)
{
expireStufferThread.interrupt();
}
if (finisherThread != null)
{
finisherThread.interrupt();
}
if (notificationThread != null)
{
notificationThread.interrupt();
}
if (workerThreads != null)
{
int i = 0;
while (i < workerThreads.length)
{
Thread workerThread = workerThreads[i++];
if (workerThread != null)
workerThread.interrupt();
}
}
if (expireThreads != null)
{
int i = 0;
while (i < expireThreads.length)
{
Thread expireThread = expireThreads[i++];
if (expireThread != null)
expireThread.interrupt();
}
}
if (cleanupStufferThread != null)
{
cleanupStufferThread.interrupt();
}
if (cleanupThreads != null)
{
int i = 0;
while (i < cleanupThreads.length)
{
Thread cleanupThread = cleanupThreads[i++];
if (cleanupThread != null)
cleanupThread.interrupt();
}
}
if (deleteStufferThread != null)
{
deleteStufferThread.interrupt();
}
if (deleteThreads != null)
{
int i = 0;
while (i < deleteThreads.length)
{
Thread deleteThread = deleteThreads[i++];
if (deleteThread != null)
deleteThread.interrupt();
}
}
if (jobResetThread != null)
{
jobResetThread.interrupt();
}
if (seedingThread != null)
{
seedingThread.interrupt();
}
if (idleCleanupThread != null)
{
idleCleanupThread.interrupt();
}
// Now, wait for all threads to die.
try
{
ManifoldCF.sleep(1000L);
}
catch (InterruptedException e)
{
}
// Check to see which died.
if (initializationThread != null)
{
if (!initializationThread.isAlive())
initializationThread = null;
}
if (setPriorityThread != null)
{
if (!setPriorityThread.isAlive())
setPriorityThread = null;
}
if (jobDeleteThread != null)
{
if (!jobDeleteThread.isAlive())
jobDeleteThread = null;
}
if (startupThread != null)
{
if (!startupThread.isAlive())
startupThread = null;
}
if (startDeleteThread != null)
{
if (!startDeleteThread.isAlive())
startDeleteThread = null;
}
if (jobStartThread != null)
{
if (!jobStartThread.isAlive())
jobStartThread = null;
}
if (stufferThread != null)
{
if (!stufferThread.isAlive())
stufferThread = null;
}
if (expireStufferThread != null)
{
if (!expireStufferThread.isAlive())
expireStufferThread = null;
}
if (finisherThread != null)
{
if (!finisherThread.isAlive())
finisherThread = null;
}
if (notificationThread != null)
{
if (!notificationThread.isAlive())
notificationThread = null;
}
if (workerThreads != null)
{
int i = 0;
boolean isAlive = false;
while (i < workerThreads.length)
{
Thread workerThread = workerThreads[i];
if (workerThread != null)
{
if (!workerThread.isAlive())
workerThreads[i] = null;
else
isAlive = true;
}
i++;
}
if (!isAlive)
workerThreads = null;
}
if (expireThreads != null)
{
int i = 0;
boolean isAlive = false;
while (i < expireThreads.length)
{
Thread expireThread = expireThreads[i];
if (expireThread != null)
{
if (!expireThread.isAlive())
expireThreads[i] = null;
else
isAlive = true;
}
i++;
}
if (!isAlive)
expireThreads = null;
}
if (cleanupStufferThread != null)
{
if (!cleanupStufferThread.isAlive())
cleanupStufferThread = null;
}
if (cleanupThreads != null)
{
int i = 0;
boolean isAlive = false;
while (i < cleanupThreads.length)
{
Thread cleanupThread = cleanupThreads[i];
if (cleanupThread != null)
{
if (!cleanupThread.isAlive())
cleanupThreads[i] = null;
else
isAlive = true;
}
i++;
}
if (!isAlive)
cleanupThreads = null;
}
if (deleteStufferThread != null)
{
if (!deleteStufferThread.isAlive())
deleteStufferThread = null;
}
if (deleteThreads != null)
{
int i = 0;
boolean isAlive = false;
while (i < deleteThreads.length)
{
Thread deleteThread = deleteThreads[i];
if (deleteThread != null)
{
if (!deleteThread.isAlive())
deleteThreads[i] = null;
else
isAlive = true;
}
i++;
}
if (!isAlive)
deleteThreads = null;
}
if (jobResetThread != null)
{
if (!jobResetThread.isAlive())
jobResetThread = null;
}
if (seedingThread != null)
{
if (!seedingThread.isAlive())
seedingThread = null;
}
if (idleCleanupThread != null)
{
if (!idleCleanupThread.isAlive())
idleCleanupThread = null;
}
}
// Threads are down; release connectors
RepositoryConnectorFactory.closeAllConnectors(threadContext);
numWorkerThreads = 0;
numDeleteThreads = 0;
numExpireThreads = 0;
}
Logging.root.info("Pull-agent successfully shut down");
}
/** Atomically export the crawler configuration */
public static void exportConfiguration(IThreadContext threadContext, String exportFilename, String passCode)
throws ManifoldCFException
{
// The basic idea here is that we open a zip stream, into which we dump all the pertinent information in a transactionally-consistent manner.
// First, we need a database handle...
IDBInterface database = DBInterfaceFactory.make(threadContext,
ManifoldCF.getMasterDatabaseName(),
ManifoldCF.getMasterDatabaseUsername(),
ManifoldCF.getMasterDatabasePassword());
// Also create the following managers, which will handle the actual details of writing configuration data
IOutputConnectionManager outputManager = OutputConnectionManagerFactory.make(threadContext);
IRepositoryConnectionManager connManager = RepositoryConnectionManagerFactory.make(threadContext);
IMappingConnectionManager mappingManager = MappingConnectionManagerFactory.make(threadContext);
IAuthorityConnectionManager authManager = AuthorityConnectionManagerFactory.make(threadContext);
IJobManager jobManager = JobManagerFactory.make(threadContext);
File outputFile = new File(exportFilename);
// Create a zip output stream, which is what we will use as a mechanism for handling the output data
try
{
OutputStream os = new FileOutputStream(outputFile);
try
{
java.util.zip.ZipOutputStream zos = null;
CipherOutputStream cos = null;
// Check whether we need to encrypt the file content:
if (passCode != null && passCode.length() > 0)
{
// Write IV as a prefix:
SecureRandom random = new SecureRandom();
byte[] iv = new byte[IV_LENGTH];
random.nextBytes(iv);
os.write(iv);
os.flush();
Cipher cipher = null;
try
{
cipher = getCipher(Cipher.ENCRYPT_MODE, passCode, iv);
}
catch (GeneralSecurityException gse)
{
throw new ManifoldCFException("Could not encrypt configuratiom file: " + gse.getMessage());
}
cos = new CipherOutputStream(os, cipher);
zos = new java.util.zip.ZipOutputStream(cos);
}
else
zos = new java.util.zip.ZipOutputStream(os);
try
{
// Now, work within a transaction.
database.beginTransaction();
try
{
// At the outermost level, I've decided that the best structure is to have a zipentry for each
// manager. Each manager must manage its own data as a binary blob, including any format versioning information,
// This guarantees flexibility for the future.
// The zipentries must be written in an order that permits their proper restoration. The "lowest level" is thus
// written first, which yields the order: authority connections, repository connections, jobs
java.util.zip.ZipEntry outputEntry = new java.util.zip.ZipEntry("outputs");
zos.putNextEntry(outputEntry);
outputManager.exportConfiguration(zos);
zos.closeEntry();
java.util.zip.ZipEntry mappingEntry = new java.util.zip.ZipEntry("mappings");
zos.putNextEntry(mappingEntry);
mappingManager.exportConfiguration(zos);
zos.closeEntry();
java.util.zip.ZipEntry authEntry = new java.util.zip.ZipEntry("authorities");
zos.putNextEntry(authEntry);
authManager.exportConfiguration(zos);
zos.closeEntry();
java.util.zip.ZipEntry connEntry = new java.util.zip.ZipEntry("connections");
zos.putNextEntry(connEntry);
connManager.exportConfiguration(zos);
zos.closeEntry();
java.util.zip.ZipEntry jobsEntry = new java.util.zip.ZipEntry("jobs");
zos.putNextEntry(jobsEntry);
jobManager.exportConfiguration(zos);
zos.closeEntry();
// All done
}
catch (ManifoldCFException e)
{
database.signalRollback();
throw e;
}
catch (Error e)
{
database.signalRollback();
throw e;
}
finally
{
database.endTransaction();
}
}
finally
{
zos.close();
if (cos != null) {
cos.close();
}
}
}
finally
{
os.close();
}
}
catch (java.io.IOException e)
{
// On error, delete any file we created
outputFile.delete();
// Convert I/O error into lcf exception
throw new ManifoldCFException("Error creating configuration file: "+e.getMessage(),e);
}
}
/** Atomically import a crawler configuration */
public static void importConfiguration(IThreadContext threadContext, String importFilename, String passCode)
throws ManifoldCFException
{
// First, we need a database handle...
IDBInterface database = DBInterfaceFactory.make(threadContext,
ManifoldCF.getMasterDatabaseName(),
ManifoldCF.getMasterDatabaseUsername(),
ManifoldCF.getMasterDatabasePassword());
// Also create the following managers, which will handle the actual details of reading configuration data
IOutputConnectionManager outputManager = OutputConnectionManagerFactory.make(threadContext);
IRepositoryConnectionManager connManager = RepositoryConnectionManagerFactory.make(threadContext);
IMappingConnectionManager mappingManager = MappingConnectionManagerFactory.make(threadContext);
IAuthorityConnectionManager authManager = AuthorityConnectionManagerFactory.make(threadContext);
IJobManager jobManager = JobManagerFactory.make(threadContext);
File inputFile = new File(importFilename);
// Create a zip input stream, which is what we will use as a mechanism for handling the input data
try
{
InputStream is = new FileInputStream(inputFile);
try
{
java.util.zip.ZipInputStream zis = null;
CipherInputStream cis = null;
// Check whether we need to decrypt the file content:
if (passCode != null && passCode.length() > 0)
{
byte[] iv = new byte[IV_LENGTH];
is.read(iv);
Cipher cipher = null;
try
{
cipher = getCipher(Cipher.DECRYPT_MODE, passCode, iv);
}
catch (GeneralSecurityException gse)
{
throw new ManifoldCFException("Could not decrypt configuratiom file: " + gse.getMessage());
}
cis = new CipherInputStream(is, cipher);
zis = new java.util.zip.ZipInputStream(cis);
}
else
zis = new java.util.zip.ZipInputStream(is);
try
{
// Now, work within a transaction.
database.beginTransaction();
try
{
// Process the entries in the order in which they were recorded.
int entries = 0;
while (true)
{
java.util.zip.ZipEntry z = zis.getNextEntry();
// Stop if there are no more entries
if (z == null)
break;
entries++;
// Get the name of the entry
String name = z.getName();
if (name.equals("outputs"))
outputManager.importConfiguration(zis);
else if (name.equals("mappings"))
mappingManager.importConfiguration(zis);
else if (name.equals("authorities"))
authManager.importConfiguration(zis);
else if (name.equals("connections"))
connManager.importConfiguration(zis);
else if (name.equals("jobs"))
jobManager.importConfiguration(zis);
else
throw new ManifoldCFException("Configuration file has an entry named '"+name+"' that I do not recognize");
zis.closeEntry();
}
if (entries == 0 && passCode != null && passCode.length() > 0)
throw new ManifoldCFException("Cannot read configuration file. Please check your passcode and/or SALT value.");
// All done!!
}
catch (ManifoldCFException e)
{
database.signalRollback();
throw e;
}
catch (Error e)
{
database.signalRollback();
throw e;
}
finally
{
database.endTransaction();
}
}
finally
{
zis.close();
if (cis != null) {
cis.close();
}
}
}
finally
{
is.close();
}
}
catch (java.io.IOException e)
{
// Convert I/O error into lcf exception
throw new ManifoldCFException("Error reading configuration file: "+e.getMessage(),e);
}
}
/** Get the maximum number of worker threads.
*/
public static int getMaxWorkerThreads()
{
return numWorkerThreads;
}
/** Get the maximum number of delete threads.
*/
public static int getMaxDeleteThreads()
{
return numDeleteThreads;
}
/** Get the maximum number of expire threads.
*/
public static int getMaxExpireThreads()
{
return numExpireThreads;
}
/** Requeue documents due to carrydown.
*/
public static void requeueDocumentsDueToCarrydown(IJobManager jobManager, DocumentDescription[] requeueCandidates,
IRepositoryConnector connector, IRepositoryConnection connection, QueueTracker queueTracker, long currentTime)
throws ManifoldCFException
{
// A list of document descriptions from finishDocuments() above represents those documents that may need to be requeued, for the
// reason that carrydown information for those documents has changed. In order to requeue, we need to calculate document priorities, however.
double[] docPriorities = new double[requeueCandidates.length];
String[][] binNames = new String[requeueCandidates.length][];
int q = 0;
while (q < requeueCandidates.length)
{
DocumentDescription dd = requeueCandidates[q];
String[] bins = calculateBins(connector,dd.getDocumentIdentifier());
binNames[q] = bins;
docPriorities[q] = queueTracker.calculatePriority(bins,connection);
if (Logging.scheduling.isDebugEnabled())
Logging.scheduling.debug("Document '"+dd.getDocumentIdentifier()+" given priority "+new Double(docPriorities[q]).toString());
q++;
}
// Now, requeue the documents with the new priorities
boolean[] trackerNote = jobManager.carrydownChangeDocumentMultiple(requeueCandidates,currentTime,docPriorities);
// Free the unused priorities.
// Inform queuetracker about what we used and what we didn't
q = 0;
while (q < trackerNote.length)
{
if (trackerNote[q] == false)
{
String[] bins = binNames[q];
queueTracker.notePriorityNotUsed(bins,connection,docPriorities[q]);
}
q++;
}
}
/** Stuff colons so we can't have conflicts. */
public static String colonStuff(String input)
{
StringBuilder sb = new StringBuilder();
int i = 0;
while (i < input.length())
{
char x = input.charAt(i++);
if (x == ':' || x == '\\')
sb.append('\\');
sb.append(x);
}
return sb.toString();
}
/** Create a global string */
public static String createGlobalString(String simpleString)
{
return ":" + simpleString;
}
/** Create a connection-specific string */
public static String createConnectionSpecificString(String connectionName, String simpleString)
{
return "C "+colonStuff(connectionName) + ":" + simpleString;
}
/** Create a job-specific string */
public static String createJobSpecificString(Long jobID, String simpleString)
{
return "J "+jobID.toString() + ":" + simpleString;
}
/** Given a connector object and a document identifier, calculate its bins.
*/
public static String[] calculateBins(IRepositoryConnector connector, String documentIdentifier)
{
// Get the bins for the document identifier
return connector.getBinNames(documentIdentifier);
}
/** Reset all (active) document priorities. This operation may occur due to various externally-triggered
* events, such a job abort, pause, resume, wait, or unwait.
*/
public static void resetAllDocumentPriorities(IThreadContext threadContext, QueueTracker queueTracker, long currentTime)
throws ManifoldCFException
{
IJobManager jobManager = JobManagerFactory.make(threadContext);
IRepositoryConnectionManager connectionManager = RepositoryConnectionManagerFactory.make(threadContext);
// Reset the queue tracker
queueTracker.beginReset();
// Perform the reprioritization, for all active documents in active jobs. During this time,
// it is safe to have other threads assign new priorities to documents, but it is NOT safe
// for other threads to attempt to change the minimum priority level. The queuetracker object
// will therefore block that from occurring, until the reset is complete.
try
{
// Reprioritize all documents in the jobqueue, 1000 at a time
HashMap connectionMap = new HashMap();
HashMap jobDescriptionMap = new HashMap();
// Do the 'not yet processed' documents only. Documents that are queued for reprocessing will be assigned
// new priorities. Already processed documents won't. This guarantees that our bins are appropriate for current thread
// activity.
// In order for this to be the correct functionality, ALL reseeding and requeuing operations MUST reset the associated document
// priorities.
while (true)
{
long startTime = System.currentTimeMillis();
DocumentDescription[] docs = jobManager.getNextNotYetProcessedReprioritizationDocuments(currentTime, 10000);
if (docs.length == 0)
break;
// Calculate new priorities for all these documents
writeDocumentPriorities(threadContext,connectionManager,jobManager,docs,connectionMap,jobDescriptionMap,queueTracker,currentTime);
Logging.threads.debug("Reprioritized "+Integer.toString(docs.length)+" not-yet-processed documents in "+new Long(System.currentTimeMillis()-startTime)+" ms");
}
}
finally
{
queueTracker.endReset();
}
}
/** Write a set of document priorities, based on the current queue tracker.
*/
public static void writeDocumentPriorities(IThreadContext threadContext, IRepositoryConnectionManager mgr, IJobManager jobManager, DocumentDescription[] descs, HashMap connectionMap, HashMap jobDescriptionMap, QueueTracker queueTracker, long currentTime)
throws ManifoldCFException
{
if (Logging.scheduling.isDebugEnabled())
Logging.scheduling.debug("Reprioritizing "+Integer.toString(descs.length)+" documents");
double[] priorities = new double[descs.length];
// Go through the documents and calculate the priorities
int i = 0;
while (i < descs.length)
{
DocumentDescription dd = descs[i];
IJobDescription job = (IJobDescription)jobDescriptionMap.get(dd.getJobID());
if (job == null)
{
job = jobManager.load(dd.getJobID(),true);
jobDescriptionMap.put(dd.getJobID(),job);
}
String connectionName = job.getConnectionName();
IRepositoryConnection connection = (IRepositoryConnection)connectionMap.get(connectionName);
if (connection == null)
{
connection = mgr.load(connectionName);
connectionMap.put(connectionName,connection);
}
String[] binNames;
// Grab a connector handle
IRepositoryConnector connector = RepositoryConnectorFactory.grab(threadContext,
connection.getClassName(),
connection.getConfigParams(),
connection.getMaxConnections());
try
{
if (connector == null)
binNames = new String[]{""};
else
// Get the bins for the document identifier
binNames = connector.getBinNames(descs[i].getDocumentIdentifier());
}
finally
{
RepositoryConnectorFactory.release(connector);
}
priorities[i] = queueTracker.calculatePriority(binNames,connection);
if (Logging.scheduling.isDebugEnabled())
Logging.scheduling.debug("Document '"+dd.getDocumentIdentifier()+"' given priority "+new Double(priorities[i]).toString());
i++;
}
// Now, write all the priorities we can.
jobManager.writeDocumentPriorities(currentTime,descs,priorities);
}
/** Request permission from agent to delete an output connection.
*@param threadContext is the thread context.
*@param connName is the name of the output connection.
*@return true if the connection is in use, false otherwise.
*/
public static boolean isOutputConnectionInUse(IThreadContext threadContext, String connName)
throws ManifoldCFException
{
// Check with job manager.
IJobManager jobManager = JobManagerFactory.make(threadContext);
return jobManager.checkIfOutputReference(connName);
}
/** Note the deregistration of a set of output connections.
*@param threadContext is the thread context.
*@param connectionNames are the names of the connections being deregistered.
*/
public static void noteOutputConnectorDeregistration(IThreadContext threadContext, String[] connectionNames)
throws ManifoldCFException
{
// Notify job manager
IJobManager jobManager = JobManagerFactory.make(threadContext);
jobManager.noteOutputConnectorDeregistration(connectionNames);
}
/** Note the registration of a set of output connections.
*@param threadContext is the thread context.
*@param connectionNames are the names of the connections being registered.
*/
public static void noteOutputConnectorRegistration(IThreadContext threadContext, String[] connectionNames)
throws ManifoldCFException
{
// Notify job manager
IJobManager jobManager = JobManagerFactory.make(threadContext);
jobManager.noteOutputConnectorRegistration(connectionNames);
}
/** Note the change in configuration of an output connection.
*@param threadContext is the thread context.
*@param connectionName is the output connection name.
*/
public static void noteOutputConnectionChange(IThreadContext threadContext, String connectionName)
throws ManifoldCFException
{
// Notify job manager
IJobManager jobManager = JobManagerFactory.make(threadContext);
jobManager.noteOutputConnectionChange(connectionName);
}
/** Qualify output activity name.
*@param outputActivityName is the name of the output activity.
*@param outputConnectionName is the corresponding name of the output connection.
*@return the qualified (global) activity name.
*/
public static String qualifyOutputActivityName(String outputActivityName, String outputConnectionName)
{
return outputActivityName+" ("+outputConnectionName+")";
}
/** Get the activities list for a given repository connection.
*/
public static String[] getActivitiesList(IThreadContext threadContext, String connectionName)
throws ManifoldCFException
{
IRepositoryConnectionManager connectionManager = RepositoryConnectionManagerFactory.make(threadContext);
IRepositoryConnection thisConnection = connectionManager.load(connectionName);
if (thisConnection == null)
return null;
String[] outputActivityList = OutputConnectionManagerFactory.getAllOutputActivities(threadContext);
String[] connectorActivityList = RepositoryConnectorFactory.getActivitiesList(threadContext,thisConnection.getClassName());
String[] globalActivityList = IRepositoryConnectionManager.activitySet;
String[] activityList = new String[outputActivityList.length + ((connectorActivityList==null)?0:connectorActivityList.length) + globalActivityList.length];
int k2 = 0;
int j;
if (outputActivityList != null)
{
j = 0;
while (j < outputActivityList.length)
{
activityList[k2++] = outputActivityList[j++];
}
}
if (connectorActivityList != null)
{
j = 0;
while (j < connectorActivityList.length)
{
activityList[k2++] = connectorActivityList[j++];
}
}
j = 0;
while (j < globalActivityList.length)
{
activityList[k2++] = globalActivityList[j++];
}
java.util.Arrays.sort(activityList);
return activityList;
}
private static final int IV_LENGTH = 16;
private static Cipher getCipher(final int mode, final String passCode, final byte[] iv) throws GeneralSecurityException,
ManifoldCFException
{
final String saltValue = getProperty(salt);
if (saltValue == null || saltValue.length() == 0)
throw new ManifoldCFException("Missing required SALT value");
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(passCode.toCharArray(), saltValue.getBytes(), 1024, 128);
SecretKey secretKey = factory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec key = new SecretKeySpec(secretKey.getEncoded(), "AES");
IvParameterSpec parameterSpec = new IvParameterSpec(iv);
cipher.init(mode, key, parameterSpec);
return cipher;
}
// ========================== API support ===========================
protected static final String API_JOBNODE = "job";
protected static final String API_JOBSTATUSNODE = "jobstatus";
protected static final String API_REPOSITORYCONNECTORNODE = "repositoryconnector";
protected static final String API_OUTPUTCONNECTORNODE = "outputconnector";
protected static final String API_AUTHORITYCONNECTORNODE = "authorityconnector";
protected static final String API_MAPPINGCONNECTORNODE = "mappingconnector";
protected static final String API_REPOSITORYCONNECTIONNODE = "repositoryconnection";
protected static final String API_OUTPUTCONNECTIONNODE = "outputconnection";
protected static final String API_AUTHORITYCONNECTIONNODE = "authorityconnection";
protected static final String API_MAPPINGCONNECTIONNODE = "mappingconnection";
protected static final String API_CHECKRESULTNODE = "check_result";
protected static final String API_JOBIDNODE = "job_id";
protected static final String API_CONNECTIONNAMENODE = "connection_name";
protected final static String API_ROWNODE = "row";
protected final static String API_COLUMNNODE = "column";
protected final static String API_NAMENODE = "name";
protected final static String API_VALUENODE = "value";
protected final static String API_ACTIVITYNODE = "activity";
// Connector nodes
protected static final String CONNECTORNODE_DESCRIPTION = "description";
protected static final String CONNECTORNODE_CLASSNAME = "class_name";
/** Decode path element.
* Path elements in the API world cannot have "/" characters, or they become impossible to parse. This method undoes
* escaping that prevents "/" from appearing.
*/
public static String decodeAPIPathElement(String startingPathElement)
throws ManifoldCFException
{
StringBuilder sb = new StringBuilder();
int i = 0;
while (i < startingPathElement.length())
{
char x = startingPathElement.charAt(i++);
if (x == '.')
{
if (i == startingPathElement.length())
throw new ManifoldCFException("Element decoding failed; illegal '.' character in '"+startingPathElement+"'");
x = startingPathElement.charAt(i++);
if (x == '.')
sb.append(x);
else if (x == '+')
sb.append('/');
else
throw new ManifoldCFException("Element decoding failed; illegal post-'.' character in '"+startingPathElement+"'");
}
else
sb.append(x);
}
return sb.toString();
}
// Read (GET) functions
// Read result codes
public static final int READRESULT_NOTFOUND = 0;
public static final int READRESULT_FOUND = 1;
/** Read jobs */
protected static int apiReadJobs(IThreadContext tc, Configuration output)
throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
IJobDescription[] jobs = jobManager.getAllJobs();
int i = 0;
while (i < jobs.length)
{
ConfigurationNode jobNode = new ConfigurationNode(API_JOBNODE);
formatJobDescription(jobNode,jobs[i++]);
output.addChild(output.getChildCount(),jobNode);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Read a job */
protected static int apiReadJob(IThreadContext tc, Configuration output, Long jobID)
throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
IJobDescription job = jobManager.load(jobID);
if (job != null)
{
// Fill the return object with job information
ConfigurationNode jobNode = new ConfigurationNode(API_JOBNODE);
formatJobDescription(jobNode,job);
output.addChild(output.getChildCount(),jobNode);
}
else
{
createErrorNode(output,"Job does not exist.");
return READRESULT_NOTFOUND;
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Read an output connection status */
protected static int apiReadOutputConnectionStatus(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
IOutputConnectionManager connectionManager = OutputConnectionManagerFactory.make(tc);
IOutputConnection connection = connectionManager.load(connectionName);
if (connection == null)
{
createErrorNode(output,"Connection '"+connectionName+"' does not exist");
return READRESULT_NOTFOUND;
}
String results;
// Grab a connection handle, and call the test method
IOutputConnector connector = OutputConnectorFactory.grab(tc,connection.getClassName(),connection.getConfigParams(),connection.getMaxConnections());
try
{
results = connector.check();
}
catch (ManifoldCFException e)
{
results = e.getMessage();
}
finally
{
OutputConnectorFactory.release(connector);
}
ConfigurationNode response = new ConfigurationNode(API_CHECKRESULTNODE);
response.setValue(results);
output.addChild(output.getChildCount(),response);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Read an authority connection status */
protected static int apiReadAuthorityConnectionStatus(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
IAuthorityConnectionManager connectionManager = AuthorityConnectionManagerFactory.make(tc);
IAuthorityConnection connection = connectionManager.load(connectionName);
if (connection == null)
{
createErrorNode(output,"Connection '"+connectionName+"' does not exist");
return READRESULT_NOTFOUND;
}
String results;
// Grab a connection handle, and call the test method
IAuthorityConnector connector = AuthorityConnectorFactory.grab(tc,connection.getClassName(),connection.getConfigParams(),connection.getMaxConnections());
try
{
results = connector.check();
}
catch (ManifoldCFException e)
{
results = e.getMessage();
}
finally
{
AuthorityConnectorFactory.release(connector);
}
ConfigurationNode response = new ConfigurationNode(API_CHECKRESULTNODE);
response.setValue(results);
output.addChild(output.getChildCount(),response);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Read a mapping connection status */
protected static int apiReadMappingConnectionStatus(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
IMappingConnectionManager connectionManager = MappingConnectionManagerFactory.make(tc);
IMappingConnection connection = connectionManager.load(connectionName);
if (connection == null)
{
createErrorNode(output,"Connection '"+connectionName+"' does not exist");
return READRESULT_NOTFOUND;
}
String results;
// Grab a connection handle, and call the test method
IMappingConnector connector = MappingConnectorFactory.grab(tc,connection.getClassName(),connection.getConfigParams(),connection.getMaxConnections());
try
{
results = connector.check();
}
catch (ManifoldCFException e)
{
results = e.getMessage();
}
finally
{
MappingConnectorFactory.release(connector);
}
ConfigurationNode response = new ConfigurationNode(API_CHECKRESULTNODE);
response.setValue(results);
output.addChild(output.getChildCount(),response);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Read a repository connection status */
protected static int apiReadRepositoryConnectionStatus(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
IRepositoryConnectionManager connectionManager = RepositoryConnectionManagerFactory.make(tc);
IRepositoryConnection connection = connectionManager.load(connectionName);
if (connection == null)
{
createErrorNode(output,"Connection '"+connectionName+"' does not exist");
return READRESULT_NOTFOUND;
}
String results;
// Grab a connection handle, and call the test method
IRepositoryConnector connector = RepositoryConnectorFactory.grab(tc,connection.getClassName(),connection.getConfigParams(),connection.getMaxConnections());
try
{
results = connector.check();
}
catch (ManifoldCFException e)
{
results = e.getMessage();
}
finally
{
RepositoryConnectorFactory.release(connector);
}
ConfigurationNode response = new ConfigurationNode(API_CHECKRESULTNODE);
response.setValue(results);
output.addChild(output.getChildCount(),response);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Read an output connection's info */
protected static int apiReadOutputConnectionInfo(IThreadContext tc, Configuration output, String connectionName, String command)
throws ManifoldCFException
{
try
{
IOutputConnectionManager connectionManager = OutputConnectionManagerFactory.make(tc);
IOutputConnection connection = connectionManager.load(connectionName);
if (connection == null)
{
createErrorNode(output,"Connection '"+connectionName+"' does not exist");
return READRESULT_NOTFOUND;
}
// Grab a connection handle, and call the test method
IOutputConnector connector = OutputConnectorFactory.grab(tc,connection.getClassName(),connection.getConfigParams(),connection.getMaxConnections());
try
{
return connector.requestInfo(output,command)?READRESULT_FOUND:READRESULT_NOTFOUND;
}
finally
{
OutputConnectorFactory.release(connector);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Read a repository connection's info */
protected static int apiReadRepositoryConnectionInfo(IThreadContext tc, Configuration output, String connectionName, String command)
throws ManifoldCFException
{
try
{
IRepositoryConnectionManager connectionManager = RepositoryConnectionManagerFactory.make(tc);
IRepositoryConnection connection = connectionManager.load(connectionName);
if (connection == null)
{
createErrorNode(output,"Connection '"+connectionName+"' does not exist");
return READRESULT_NOTFOUND;
}
// Grab a connection handle, and call the test method
IRepositoryConnector connector = RepositoryConnectorFactory.grab(tc,connection.getClassName(),connection.getConfigParams(),connection.getMaxConnections());
try
{
return connector.requestInfo(output,command)?READRESULT_FOUND:READRESULT_NOTFOUND;
}
finally
{
RepositoryConnectorFactory.release(connector);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Get api job statuses */
protected static int apiReadJobStatuses(IThreadContext tc, Configuration output)
throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
JobStatus[] jobStatuses = jobManager.getAllStatus();
int i = 0;
while (i < jobStatuses.length)
{
ConfigurationNode jobStatusNode = new ConfigurationNode(API_JOBSTATUSNODE);
formatJobStatus(jobStatusNode,jobStatuses[i++]);
output.addChild(output.getChildCount(),jobStatusNode);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Get api job status */
protected static int apiReadJobStatus(IThreadContext tc, Configuration output, Long jobID)
throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
JobStatus status = jobManager.getStatus(jobID);
if (status != null)
{
ConfigurationNode jobStatusNode = new ConfigurationNode(API_JOBSTATUSNODE);
formatJobStatus(jobStatusNode,status);
output.addChild(output.getChildCount(),jobStatusNode);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Get api job status with no counts */
protected static int apiReadJobStatusNoCounts(IThreadContext tc, Configuration output, Long jobID)
throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
JobStatus status = jobManager.getStatus(jobID,false);
if (status != null)
{
ConfigurationNode jobStatusNode = new ConfigurationNode(API_JOBSTATUSNODE);
formatJobStatus(jobStatusNode,status);
output.addChild(output.getChildCount(),jobStatusNode);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Get output connections */
protected static int apiReadOutputConnections(IThreadContext tc, Configuration output)
throws ManifoldCFException
{
try
{
IOutputConnectionManager connManager = OutputConnectionManagerFactory.make(tc);
IOutputConnection[] connections = connManager.getAllConnections();
int i = 0;
while (i < connections.length)
{
ConfigurationNode connectionNode = new ConfigurationNode(API_OUTPUTCONNECTIONNODE);
formatOutputConnection(connectionNode,connections[i++]);
output.addChild(output.getChildCount(),connectionNode);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Read output connection */
protected static int apiReadOutputConnection(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
IOutputConnectionManager connectionManager = OutputConnectionManagerFactory.make(tc);
IOutputConnection connection = connectionManager.load(connectionName);
if (connection != null)
{
// Fill the return object with job information
ConfigurationNode connectionNode = new ConfigurationNode(API_OUTPUTCONNECTIONNODE);
formatOutputConnection(connectionNode,connection);
output.addChild(output.getChildCount(),connectionNode);
}
else
{
createErrorNode(output,"Connection '"+connectionName+"' does not exist.");
return READRESULT_NOTFOUND;
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Get authority connections */
protected static int apiReadAuthorityConnections(IThreadContext tc, Configuration output)
throws ManifoldCFException
{
try
{
IAuthorityConnectionManager connManager = AuthorityConnectionManagerFactory.make(tc);
IAuthorityConnection[] connections = connManager.getAllConnections();
int i = 0;
while (i < connections.length)
{
ConfigurationNode connectionNode = new ConfigurationNode(API_AUTHORITYCONNECTIONNODE);
formatAuthorityConnection(connectionNode,connections[i++]);
output.addChild(output.getChildCount(),connectionNode);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Get mapping connections */
protected static int apiReadMappingConnections(IThreadContext tc, Configuration output)
throws ManifoldCFException
{
try
{
IMappingConnectionManager connManager = MappingConnectionManagerFactory.make(tc);
IMappingConnection[] connections = connManager.getAllConnections();
int i = 0;
while (i < connections.length)
{
ConfigurationNode connectionNode = new ConfigurationNode(API_MAPPINGCONNECTIONNODE);
formatMappingConnection(connectionNode,connections[i++]);
output.addChild(output.getChildCount(),connectionNode);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Read authority connection */
protected static int apiReadAuthorityConnection(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
IAuthorityConnectionManager connectionManager = AuthorityConnectionManagerFactory.make(tc);
IAuthorityConnection connection = connectionManager.load(connectionName);
if (connection != null)
{
// Fill the return object with job information
ConfigurationNode connectionNode = new ConfigurationNode(API_AUTHORITYCONNECTIONNODE);
formatAuthorityConnection(connectionNode,connection);
output.addChild(output.getChildCount(),connectionNode);
}
else
{
createErrorNode(output,"Authority connection '"+connectionName+"' does not exist.");
return READRESULT_NOTFOUND;
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Read mapping connection */
protected static int apiReadMappingConnection(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
IMappingConnectionManager connectionManager = MappingConnectionManagerFactory.make(tc);
IMappingConnection connection = connectionManager.load(connectionName);
if (connection != null)
{
// Fill the return object with job information
ConfigurationNode connectionNode = new ConfigurationNode(API_MAPPINGCONNECTIONNODE);
formatMappingConnection(connectionNode,connection);
output.addChild(output.getChildCount(),connectionNode);
}
else
{
createErrorNode(output,"Mapping connection '"+connectionName+"' does not exist.");
return READRESULT_NOTFOUND;
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Get repository connections */
protected static int apiReadRepositoryConnections(IThreadContext tc, Configuration output)
throws ManifoldCFException
{
try
{
IRepositoryConnectionManager connManager = RepositoryConnectionManagerFactory.make(tc);
IRepositoryConnection[] connections = connManager.getAllConnections();
int i = 0;
while (i < connections.length)
{
ConfigurationNode connectionNode = new ConfigurationNode(API_REPOSITORYCONNECTIONNODE);
formatRepositoryConnection(connectionNode,connections[i++]);
output.addChild(output.getChildCount(),connectionNode);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Read repository connection */
protected static int apiReadRepositoryConnection(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
IRepositoryConnectionManager connectionManager = RepositoryConnectionManagerFactory.make(tc);
IRepositoryConnection connection = connectionManager.load(connectionName);
if (connection != null)
{
// Fill the return object with job information
ConfigurationNode connectionNode = new ConfigurationNode(API_REPOSITORYCONNECTIONNODE);
formatRepositoryConnection(connectionNode,connection);
output.addChild(output.getChildCount(),connectionNode);
}
else
{
createErrorNode(output,"Repository connection '"+connectionName+"' does not exist");
return READRESULT_NOTFOUND;
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** List output connectors */
protected static int apiReadOutputConnectors(IThreadContext tc, Configuration output)
throws ManifoldCFException
{
// List registered output connectors
try
{
IOutputConnectorManager manager = OutputConnectorManagerFactory.make(tc);
IResultSet resultSet = manager.getConnectors();
int j = 0;
while (j < resultSet.getRowCount())
{
IResultRow row = resultSet.getRow(j++);
ConfigurationNode child = new ConfigurationNode(API_OUTPUTCONNECTORNODE);
String description = (String)row.getValue("description");
String className = (String)row.getValue("classname");
ConfigurationNode node;
if (description != null)
{
node = new ConfigurationNode(CONNECTORNODE_DESCRIPTION);
node.setValue(description);
child.addChild(child.getChildCount(),node);
}
node = new ConfigurationNode(CONNECTORNODE_CLASSNAME);
node.setValue(className);
child.addChild(child.getChildCount(),node);
output.addChild(output.getChildCount(),child);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** List authority connectors */
protected static int apiReadAuthorityConnectors(IThreadContext tc, Configuration output)
throws ManifoldCFException
{
// List registered authority connectors
try
{
IAuthorityConnectorManager manager = AuthorityConnectorManagerFactory.make(tc);
IResultSet resultSet = manager.getConnectors();
int j = 0;
while (j < resultSet.getRowCount())
{
IResultRow row = resultSet.getRow(j++);
ConfigurationNode child = new ConfigurationNode(API_AUTHORITYCONNECTORNODE);
String description = (String)row.getValue("description");
String className = (String)row.getValue("classname");
ConfigurationNode node;
if (description != null)
{
node = new ConfigurationNode(CONNECTORNODE_DESCRIPTION);
node.setValue(description);
child.addChild(child.getChildCount(),node);
}
node = new ConfigurationNode(CONNECTORNODE_CLASSNAME);
node.setValue(className);
child.addChild(child.getChildCount(),node);
output.addChild(output.getChildCount(),child);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** List mapping connectors */
protected static int apiReadMappingConnectors(IThreadContext tc, Configuration output)
throws ManifoldCFException
{
// List registered authority connectors
try
{
IMappingConnectorManager manager = MappingConnectorManagerFactory.make(tc);
IResultSet resultSet = manager.getConnectors();
int j = 0;
while (j < resultSet.getRowCount())
{
IResultRow row = resultSet.getRow(j++);
ConfigurationNode child = new ConfigurationNode(API_MAPPINGCONNECTORNODE);
String description = (String)row.getValue("description");
String className = (String)row.getValue("classname");
ConfigurationNode node;
if (description != null)
{
node = new ConfigurationNode(CONNECTORNODE_DESCRIPTION);
node.setValue(description);
child.addChild(child.getChildCount(),node);
}
node = new ConfigurationNode(CONNECTORNODE_CLASSNAME);
node.setValue(className);
child.addChild(child.getChildCount(),node);
output.addChild(output.getChildCount(),child);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** List repository connectors */
protected static int apiReadRepositoryConnectors(IThreadContext tc, Configuration output)
throws ManifoldCFException
{
// List registered repository connectors
try
{
IConnectorManager manager = ConnectorManagerFactory.make(tc);
IResultSet resultSet = manager.getConnectors();
int j = 0;
while (j < resultSet.getRowCount())
{
IResultRow row = resultSet.getRow(j++);
ConfigurationNode child = new ConfigurationNode(API_REPOSITORYCONNECTORNODE);
String description = (String)row.getValue("description");
String className = (String)row.getValue("classname");
ConfigurationNode node;
if (description != null)
{
node = new ConfigurationNode(CONNECTORNODE_DESCRIPTION);
node.setValue(description);
child.addChild(child.getChildCount(),node);
}
node = new ConfigurationNode(CONNECTORNODE_CLASSNAME);
node.setValue(className);
child.addChild(child.getChildCount(),node);
output.addChild(output.getChildCount(),child);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
protected final static Map<String,Integer> docState;
static
{
docState = new HashMap<String,Integer>();
docState.put("neverprocessed",new Integer(IJobManager.DOCSTATE_NEVERPROCESSED));
docState.put("previouslyprocessed",new Integer(IJobManager.DOCSTATE_PREVIOUSLYPROCESSED));
docState.put("outofscope",new Integer(IJobManager.DOCSTATE_OUTOFSCOPE));
}
protected final static Map<String,Integer> docStatus;
static
{
docStatus = new HashMap<String,Integer>();
docStatus.put("inactive",new Integer(IJobManager.DOCSTATUS_INACTIVE));
docStatus.put("processing",new Integer(IJobManager.DOCSTATUS_PROCESSING));
docStatus.put("expiring",new Integer(IJobManager.DOCSTATUS_EXPIRING));
docStatus.put("deleting",new Integer(IJobManager.DOCSTATUS_DELETING));
docStatus.put("readyforprocessing",new Integer(IJobManager.DOCSTATUS_READYFORPROCESSING));
docStatus.put("readyforexpiration",new Integer(IJobManager.DOCSTATUS_READYFOREXPIRATION));
docStatus.put("waitingforprocessing",new Integer(IJobManager.DOCSTATUS_WAITINGFORPROCESSING));
docStatus.put("waitingforexpiration",new Integer(IJobManager.DOCSTATUS_WAITINGFOREXPIRATION));
docStatus.put("waitingforever",new Integer(IJobManager.DOCSTATUS_WAITINGFOREVER));
docStatus.put("hopcountexceeded",new Integer(IJobManager.DOCSTATUS_HOPCOUNTEXCEEDED));
}
/** Queue reports */
protected static int apiReadRepositoryConnectionQueue(IThreadContext tc, Configuration output,
String connectionName, Map<String,List<String>> queryParameters) throws ManifoldCFException
{
if (queryParameters == null)
queryParameters = new HashMap<String,List<String>>();
// Jobs (specified by id)
Long[] jobs;
List<String> jobList = queryParameters.get("job");
if (jobList == null)
jobs = new Long[0];
else
{
jobs = new Long[jobList.size()];
for (int i = 0; i < jobs.length; i++)
{
jobs[i] = new Long(jobList.get(i));
}
}
// Now time
long now;
List<String> nowList = queryParameters.get("now");
if (nowList == null || nowList.size() == 0)
now = System.currentTimeMillis();
else if (nowList.size() > 1)
throw new ManifoldCFException("Multiple values for now parameter");
else
now = new Long(nowList.get(0)).longValue();
// Identifier match
RegExpCriteria idMatch;
List<String> idMatchList = queryParameters.get("idmatch");
List<String> idMatchInsensitiveList = queryParameters.get("idmatch_insensitive");
if (idMatchList != null && idMatchInsensitiveList != null)
throw new ManifoldCFException("Either use idmatch or idmatch_insensitive, not both.");
boolean isInsensitiveIdMatch;
if (idMatchInsensitiveList != null)
{
idMatchList = idMatchInsensitiveList;
isInsensitiveIdMatch = true;
}
else
isInsensitiveIdMatch = false;
if (idMatchList == null || idMatchList.size() == 0)
idMatch = null;
else if (idMatchList.size() > 1)
throw new ManifoldCFException("Multiple id match regexps specified.");
else
idMatch = new RegExpCriteria(idMatchList.get(0),isInsensitiveIdMatch);
List<String> stateMatchList = queryParameters.get("statematch");
int[] matchStates;
if (stateMatchList == null)
matchStates = new int[0];
else
{
matchStates = new int[stateMatchList.size()];
for (int i = 0; i < matchStates.length; i++)
{
Integer value = docState.get(stateMatchList.get(i));
if (value == null)
throw new ManifoldCFException("Unrecognized state value: '"+stateMatchList.get(i)+"'");
matchStates[i] = value.intValue();
}
}
List<String> statusMatchList = queryParameters.get("statusmatch");
int[] matchStatuses;
if (statusMatchList == null)
matchStatuses = new int[0];
else
{
matchStatuses = new int[statusMatchList.size()];
for (int i = 0; i < matchStatuses.length; i++)
{
Integer value = docStatus.get(statusMatchList.get(i));
if (value == null)
throw new ManifoldCFException("Unrecognized status value: '"+statusMatchList.get(i)+"'");
matchStatuses[i] = value.intValue();
}
}
StatusFilterCriteria filterCriteria = new StatusFilterCriteria(jobs,now,idMatch,matchStates,matchStatuses);
// Look for sort order parameters...
SortOrder sortOrder = new SortOrder();
List<String> sortColumnsList = queryParameters.get("sortcolumn");
List<String> sortColumnsDirList = queryParameters.get("sortcolumn_direction");
if (sortColumnsList != null || sortColumnsDirList != null)
{
if (sortColumnsList == null || sortColumnsDirList == null || sortColumnsList.size() != sortColumnsDirList.size())
throw new ManifoldCFException("sortcolumn and sortcolumn_direction must have the same cardinality.");
for (int i = 0; i < sortColumnsList.size(); i++)
{
String column = sortColumnsList.get(i);
String dir = sortColumnsDirList.get(i);
int dirInt;
if (dir.equals("ascending"))
dirInt = SortOrder.SORT_ASCENDING;
else if (dir.equals("descending"))
dirInt = SortOrder.SORT_DESCENDING;
else
throw new ManifoldCFException("sortcolumn_direction must be 'ascending' or 'descending'.");
sortOrder.addCriteria(column,dirInt);
}
}
// Start row and row count
int startRow;
List<String> startRowList = queryParameters.get("startrow");
if (startRowList == null || startRowList.size() == 0)
startRow = 0;
else if (startRowList.size() > 1)
throw new ManifoldCFException("Multiple start rows specified.");
else
startRow = new Integer(startRowList.get(0)).intValue();
int rowCount;
List<String> rowCountList = queryParameters.get("rowcount");
if (rowCountList == null || rowCountList.size() == 0)
rowCount = 20;
else if (rowCountList.size() > 1)
throw new ManifoldCFException("Multiple row counts specified.");
else
rowCount = new Integer(rowCountList.get(0)).intValue();
List<String> reportTypeList = queryParameters.get("report");
String reportType;
if (reportTypeList == null || reportTypeList.size() == 0)
reportType = "document";
else if (reportTypeList.size() > 1)
throw new ManifoldCFException("Multiple report types specified.");
else
reportType = reportTypeList.get(0);
IJobManager jobManager = JobManagerFactory.make(tc);
IResultSet result;
String[] resultColumns;
if (reportType.equals("document"))
{
try
{
result = jobManager.genDocumentStatus(connectionName,filterCriteria,sortOrder,startRow,rowCount);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
return READRESULT_FOUND;
}
resultColumns = new String[]{"identifier","job","state","status","scheduled","action","retrycount","retrylimit"};
}
else if (reportType.equals("status"))
{
BucketDescription idBucket;
List<String> idBucketList = queryParameters.get("idbucket");
List<String> idBucketInsensitiveList = queryParameters.get("idbucket_insensitive");
if (idBucketList != null && idBucketInsensitiveList != null)
throw new ManifoldCFException("Either use idbucket or idbucket_insensitive, not both.");
boolean isInsensitiveIdBucket;
if (idBucketInsensitiveList != null)
{
idBucketList = idBucketInsensitiveList;
isInsensitiveIdBucket = true;
}
else
isInsensitiveIdBucket = false;
if (idBucketList == null || idBucketList.size() == 0)
idBucket = new BucketDescription("()",false);
else if (idBucketList.size() > 1)
throw new ManifoldCFException("Multiple idbucket regexps specified.");
else
idBucket = new BucketDescription(idBucketList.get(0),isInsensitiveIdBucket);
try
{
result = jobManager.genQueueStatus(connectionName,filterCriteria,sortOrder,idBucket,startRow,rowCount);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
return READRESULT_FOUND;
}
resultColumns = new String[]{"idbucket","inactive","processing","expiring","deleting",
"processready","expireready","processwaiting","expirewaiting","waitingforever","hopcountexceeded"};
}
else
throw new ManifoldCFException("Unknown report type '"+reportType+"'.");
createResultsetNode(output,result,resultColumns);
return READRESULT_FOUND;
}
/** Get jobs for connection */
protected static int apiReadRepositoryConnectionJobs(IThreadContext tc, Configuration output,
String connectionName) throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
IJobDescription[] jobs = jobManager.findJobsForConnection(connectionName);
if (jobs == null)
{
createErrorNode(output,"Unknown connection '"+connectionName+"'");
return READRESULT_NOTFOUND;
}
int i = 0;
while (i < jobs.length)
{
ConfigurationNode jobNode = new ConfigurationNode(API_JOBNODE);
formatJobDescription(jobNode,jobs[i++]);
output.addChild(output.getChildCount(),jobNode);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** History reports */
protected static int apiReadRepositoryConnectionHistory(IThreadContext tc, Configuration output,
String connectionName, Map<String,List<String>> queryParameters) throws ManifoldCFException
{
if (queryParameters == null)
queryParameters = new HashMap<String,List<String>>();
// Look for filter criteria parameters...
// Start time
List<String> startTimeList = queryParameters.get("starttime");
Long startTime;
if (startTimeList == null || startTimeList.size() == 0)
startTime = null;
else if (startTimeList.size() > 1)
throw new ManifoldCFException("Multiple start times specified.");
else
startTime = new Long(startTimeList.get(0));
// End time
List<String> endTimeList = queryParameters.get("endtime");
Long endTime;
if (endTimeList == null || endTimeList.size() == 0)
endTime = null;
else if (endTimeList.size() > 1)
throw new ManifoldCFException("Multiple end times specified.");
else
endTime = new Long(endTimeList.get(0));
// Activities
List<String> activityList = queryParameters.get("activity");
String[] activities;
if (activityList == null)
activities = new String[0];
else
activities = activityList.toArray(new String[0]);
// Entity match
RegExpCriteria entityMatch;
List<String> entityMatchList = queryParameters.get("entitymatch");
List<String> entityMatchInsensitiveList = queryParameters.get("entitymatch_insensitive");
if (entityMatchList != null && entityMatchInsensitiveList != null)
throw new ManifoldCFException("Either use entitymatch or entitymatch_insensitive, not both.");
boolean isInsensitiveEntityMatch;
if (entityMatchInsensitiveList != null)
{
entityMatchList = entityMatchInsensitiveList;
isInsensitiveEntityMatch = true;
}
else
isInsensitiveEntityMatch = false;
if (entityMatchList == null || entityMatchList.size() == 0)
entityMatch = null;
else if (entityMatchList.size() > 1)
throw new ManifoldCFException("Multiple entity match regexps specified.");
else
entityMatch = new RegExpCriteria(entityMatchList.get(0),isInsensitiveEntityMatch);
// Result code match
RegExpCriteria resultCodeMatch;
List<String> resultCodeMatchList = queryParameters.get("resultcodematch");
List<String> resultCodeMatchInsensitiveList = queryParameters.get("resultcodematch_insensitive");
if (resultCodeMatchList != null && resultCodeMatchInsensitiveList != null)
throw new ManifoldCFException("Either use resultcodematch or resultcodematch_insensitive, not both.");
boolean isInsensitiveResultCodeMatch;
if (entityMatchInsensitiveList != null)
{
resultCodeMatchList = resultCodeMatchInsensitiveList;
isInsensitiveResultCodeMatch = true;
}
else
isInsensitiveResultCodeMatch = false;
if (resultCodeMatchList == null || resultCodeMatchList.size() == 0)
resultCodeMatch = null;
else if (resultCodeMatchList.size() > 1)
throw new ManifoldCFException("Multiple resultcode match regexps specified.");
else
resultCodeMatch = new RegExpCriteria(resultCodeMatchList.get(0),isInsensitiveResultCodeMatch);
// Filter criteria
FilterCriteria filterCriteria = new FilterCriteria(activities,startTime,endTime,entityMatch,resultCodeMatch);
// Look for sort order parameters...
SortOrder sortOrder = new SortOrder();
List<String> sortColumnsList = queryParameters.get("sortcolumn");
List<String> sortColumnsDirList = queryParameters.get("sortcolumn_direction");
if (sortColumnsList != null || sortColumnsDirList != null)
{
if (sortColumnsList == null || sortColumnsDirList == null || sortColumnsList.size() != sortColumnsDirList.size())
throw new ManifoldCFException("sortcolumn and sortcolumn_direction must have the same cardinality.");
for (int i = 0; i < sortColumnsList.size(); i++)
{
String column = sortColumnsList.get(i);
String dir = sortColumnsDirList.get(i);
int dirInt;
if (dir.equals("ascending"))
dirInt = SortOrder.SORT_ASCENDING;
else if (dir.equals("descending"))
dirInt = SortOrder.SORT_DESCENDING;
else
throw new ManifoldCFException("sortcolumn_direction must be 'ascending' or 'descending'.");
sortOrder.addCriteria(column,dirInt);
}
}
// Start row and row count
int startRow;
List<String> startRowList = queryParameters.get("startrow");
if (startRowList == null || startRowList.size() == 0)
startRow = 0;
else if (startRowList.size() > 1)
throw new ManifoldCFException("Multiple start rows specified.");
else
startRow = new Integer(startRowList.get(0)).intValue();
int rowCount;
List<String> rowCountList = queryParameters.get("rowcount");
if (rowCountList == null || rowCountList.size() == 0)
rowCount = 20;
else if (rowCountList.size() > 1)
throw new ManifoldCFException("Multiple row counts specified.");
else
rowCount = new Integer(rowCountList.get(0)).intValue();
List<String> reportTypeList = queryParameters.get("report");
String reportType;
if (reportTypeList == null || reportTypeList.size() == 0)
reportType = "simple";
else if (reportTypeList.size() > 1)
throw new ManifoldCFException("Multiple report types specified.");
else
reportType = reportTypeList.get(0);
IRepositoryConnectionManager connectionManager = RepositoryConnectionManagerFactory.make(tc);
IResultSet result;
String[] resultColumns;
if (reportType.equals("simple"))
{
try
{
result = connectionManager.genHistorySimple(connectionName,filterCriteria,sortOrder,startRow,rowCount);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
return READRESULT_FOUND;
}
resultColumns = new String[]{"starttime","resultcode","resultdesc","identifier","activity","bytes","elapsedtime"};
}
else if (reportType.equals("maxactivity"))
{
long maxInterval = connectionManager.getMaxRows();
long actualRows = connectionManager.countHistoryRows(connectionName,filterCriteria);
if (actualRows > maxInterval)
throw new ManifoldCFException("Too many history rows specified for maxactivity report - actual is "+actualRows+", max is "+maxInterval+".");
BucketDescription idBucket;
List<String> idBucketList = queryParameters.get("idbucket");
List<String> idBucketInsensitiveList = queryParameters.get("idbucket_insensitive");
if (idBucketList != null && idBucketInsensitiveList != null)
throw new ManifoldCFException("Either use idbucket or idbucket_insensitive, not both.");
boolean isInsensitiveIdBucket;
if (idBucketInsensitiveList != null)
{
idBucketList = idBucketInsensitiveList;
isInsensitiveIdBucket = true;
}
else
isInsensitiveIdBucket = false;
if (idBucketList == null || idBucketList.size() == 0)
idBucket = new BucketDescription("()",false);
else if (idBucketList.size() > 1)
throw new ManifoldCFException("Multiple idbucket regexps specified.");
else
idBucket = new BucketDescription(idBucketList.get(0),isInsensitiveIdBucket);
long interval;
List<String> intervalList = queryParameters.get("interval");
if (intervalList == null || intervalList.size() == 0)
interval = 300000L;
else if (intervalList.size() > 1)
throw new ManifoldCFException("Multiple intervals specified.");
else
interval = new Long(intervalList.get(0)).longValue();
try
{
result = connectionManager.genHistoryActivityCount(connectionName,filterCriteria,sortOrder,idBucket,interval,startRow,rowCount);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
return READRESULT_FOUND;
}
resultColumns = new String[]{"starttime","endtime","activitycount","idbucket"};
}
else if (reportType.equals("maxbandwidth"))
{
long maxInterval = connectionManager.getMaxRows();
long actualRows = connectionManager.countHistoryRows(connectionName,filterCriteria);
if (actualRows > maxInterval)
throw new ManifoldCFException("Too many history rows specified for maxbandwidth report - actual is "+actualRows+", max is "+maxInterval+".");
BucketDescription idBucket;
List<String> idBucketList = queryParameters.get("idbucket");
List<String> idBucketInsensitiveList = queryParameters.get("idbucket_insensitive");
if (idBucketList != null && idBucketInsensitiveList != null)
throw new ManifoldCFException("Either use idbucket or idbucket_insensitive, not both.");
boolean isInsensitiveIdBucket;
if (idBucketInsensitiveList != null)
{
idBucketList = idBucketInsensitiveList;
isInsensitiveIdBucket = true;
}
else
isInsensitiveIdBucket = false;
if (idBucketList == null || idBucketList.size() == 0)
idBucket = new BucketDescription("()",false);
else if (idBucketList.size() > 1)
throw new ManifoldCFException("Multiple idbucket regexps specified.");
else
idBucket = new BucketDescription(idBucketList.get(0),isInsensitiveIdBucket);
long interval;
List<String> intervalList = queryParameters.get("interval");
if (intervalList == null || intervalList.size() == 0)
interval = 300000L;
else if (intervalList.size() > 1)
throw new ManifoldCFException("Multiple intervals specified.");
else
interval = new Long(intervalList.get(0)).longValue();
try
{
result = connectionManager.genHistoryByteCount(connectionName,filterCriteria,sortOrder,idBucket,interval,startRow,rowCount);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
return READRESULT_FOUND;
}
resultColumns = new String[]{"starttime","endtime","bytecount","idbucket"};
}
else if (reportType.equals("result"))
{
BucketDescription idBucket;
List<String> idBucketList = queryParameters.get("idbucket");
List<String> idBucketInsensitiveList = queryParameters.get("idbucket_insensitive");
if (idBucketList != null && idBucketInsensitiveList != null)
throw new ManifoldCFException("Either use idbucket or idbucket_insensitive, not both.");
boolean isInsensitiveIdBucket;
if (idBucketInsensitiveList != null)
{
idBucketList = idBucketInsensitiveList;
isInsensitiveIdBucket = true;
}
else
isInsensitiveIdBucket = false;
if (idBucketList == null || idBucketList.size() == 0)
idBucket = new BucketDescription("()",false);
else if (idBucketList.size() > 1)
throw new ManifoldCFException("Multiple idbucket regexps specified.");
else
idBucket = new BucketDescription(idBucketList.get(0),isInsensitiveIdBucket);
BucketDescription resultCodeBucket;
List<String> resultCodeBucketList = queryParameters.get("resultcodebucket");
List<String> resultCodeBucketInsensitiveList = queryParameters.get("resultcodebucket_insensitive");
if (resultCodeBucketList != null && resultCodeBucketInsensitiveList != null)
throw new ManifoldCFException("Either use resultcodebucket or resultcodebucket_insensitive, not both.");
boolean isInsensitiveResultCodeBucket;
if (resultCodeBucketInsensitiveList != null)
{
resultCodeBucketList = resultCodeBucketInsensitiveList;
isInsensitiveResultCodeBucket = true;
}
else
isInsensitiveResultCodeBucket = false;
if (resultCodeBucketList == null || resultCodeBucketList.size() == 0)
resultCodeBucket = new BucketDescription("(.*)",false);
else if (resultCodeBucketList.size() > 1)
throw new ManifoldCFException("Multiple resultcodebucket regexps specified.");
else
resultCodeBucket = new BucketDescription(resultCodeBucketList.get(0),isInsensitiveResultCodeBucket);
try
{
result = connectionManager.genHistoryResultCodes(connectionName,filterCriteria,sortOrder,resultCodeBucket,idBucket,startRow,rowCount);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
return READRESULT_FOUND;
}
resultColumns = new String[]{"idbucket","resultcodebucket","eventcount"};
}
else
throw new ManifoldCFException("Unknown report type '"+reportType+"'.");
createResultsetNode(output,result,resultColumns);
return READRESULT_FOUND;
}
/** Add a resultset node to the output. */
protected static void createResultsetNode(Configuration output, IResultSet result, String[] resultColumns)
throws ManifoldCFException
{
// Go through result set and add results to output
for (int i = 0; i < result.getRowCount(); i++)
{
IResultRow row = result.getRow(i);
ConfigurationNode rowValue = new ConfigurationNode(API_ROWNODE);
for (String columnName : resultColumns)
{
ConfigurationNode columnValue = new ConfigurationNode(API_COLUMNNODE);
Object value = row.getValue(columnName);
String valueToUse;
if (value == null)
valueToUse = "";
else
valueToUse = value.toString();
ConfigurationNode nameNode = new ConfigurationNode(API_NAMENODE);
nameNode.setValue(columnName);
columnValue.addChild(columnValue.getChildCount(),nameNode);
ConfigurationNode valueNode = new ConfigurationNode(API_VALUENODE);
valueNode.setValue(valueToUse);
columnValue.addChild(columnValue.getChildCount(),valueNode);
rowValue.addChild(rowValue.getChildCount(),columnValue);
}
output.addChild(output.getChildCount(),rowValue);
}
}
/** Read the activity list for a given connection name. */
protected static int apiReadRepositoryConnectionActivities(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
String[] activities = getActivitiesList(tc,connectionName);
if (activities == null)
{
createErrorNode(output,"Connection '"+connectionName+"' does not exist.");
return READRESULT_NOTFOUND;
}
for (String activity : activities)
{
ConfigurationNode node = new ConfigurationNode(API_ACTIVITYNODE);
node.setValue(activity);
output.addChild(output.getChildCount(),node);
}
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return READRESULT_FOUND;
}
/** Execute specified read command.
*@param tc is the thread context.
*@param output is the output object, to be filled in.
*@param path is the object path.
*@return read status - either found, not found, or bad args
*/
public static int executeReadCommand(IThreadContext tc, Configuration output, String path,
Map<String,List<String>> queryParameters) throws ManifoldCFException
{
if (path.equals("jobs"))
{
return apiReadJobs(tc,output);
}
else if (path.startsWith("jobs/"))
{
Long jobID = new Long(path.substring("jobs/".length()));
return apiReadJob(tc,output,jobID);
}
else if (path.startsWith("repositoryconnectionactivities/"))
{
int firstSeparator = "repositoryconnectionactivities/".length();
String connectionName = decodeAPIPathElement(path.substring(firstSeparator));
return apiReadRepositoryConnectionActivities(tc,output,connectionName);
}
else if (path.startsWith("repositoryconnectionhistory/"))
{
int firstSeparator = "repositoryconnectionhistory/".length();
String connectionName = decodeAPIPathElement(path.substring(firstSeparator));
return apiReadRepositoryConnectionHistory(tc,output,connectionName,queryParameters);
}
else if (path.startsWith("repositoryconnectionqueue/"))
{
int firstSeparator = "repositoryconnectionqueue/".length();
String connectionName = decodeAPIPathElement(path.substring(firstSeparator));
return apiReadRepositoryConnectionQueue(tc,output,connectionName,queryParameters);
}
else if (path.startsWith("repositoryconnectionjobs/"))
{
int firstSeparator = "repositoryconnectionjobs/".length();
String connectionName = decodeAPIPathElement(path.substring(firstSeparator));
return apiReadRepositoryConnectionJobs(tc,output,connectionName);
}
else if (path.startsWith("status/"))
{
int firstSeparator = "status/".length();
int secondSeparator = path.indexOf("/",firstSeparator);
if (secondSeparator == -1)
{
createErrorNode(output,"Need connection name.");
return READRESULT_NOTFOUND;
}
String connectionType = path.substring(firstSeparator,secondSeparator);
String connectionName = decodeAPIPathElement(path.substring(secondSeparator+1));
if (connectionType.equals("outputconnections"))
{
return apiReadOutputConnectionStatus(tc,output,connectionName);
}
else if (connectionType.equals("mappingconnections"))
{
return apiReadMappingConnectionStatus(tc,output,connectionName);
}
else if (connectionType.equals("authorityconnections"))
{
return apiReadAuthorityConnectionStatus(tc,output,connectionName);
}
else if (connectionType.equals("repositoryconnections"))
{
return apiReadRepositoryConnectionStatus(tc,output,connectionName);
}
else
{
createErrorNode(output,"Unknown connection type '"+connectionType+"'.");
return READRESULT_NOTFOUND;
}
}
else if (path.startsWith("info/"))
{
int firstSeparator = "info/".length();
int secondSeparator = path.indexOf("/",firstSeparator);
if (secondSeparator == -1)
{
createErrorNode(output,"Need connection type and connection name.");
return READRESULT_NOTFOUND;
}
int thirdSeparator = path.indexOf("/",secondSeparator+1);
if (thirdSeparator == -1)
{
createErrorNode(output,"Need connection name.");
return READRESULT_NOTFOUND;
}
String connectionType = path.substring(firstSeparator,secondSeparator);
String connectionName = decodeAPIPathElement(path.substring(secondSeparator+1,thirdSeparator));
String command = path.substring(thirdSeparator+1);
if (connectionType.equals("outputconnections"))
{
return apiReadOutputConnectionInfo(tc,output,connectionName,command);
}
else if (connectionType.equals("repositoryconnections"))
{
return apiReadRepositoryConnectionInfo(tc,output,connectionName,command);
}
else
{
createErrorNode(output,"Unknown connection type '"+connectionType+"'.");
return READRESULT_NOTFOUND;
}
}
else if (path.equals("jobstatuses"))
{
return apiReadJobStatuses(tc,output);
}
else if (path.startsWith("jobstatuses/"))
{
Long jobID = new Long(path.substring("jobstatuses/".length()));
return apiReadJobStatus(tc,output,jobID);
}
else if (path.startsWith("jobstatusesnocounts/"))
{
Long jobID = new Long(path.substring("jobstatusesnocounts/".length()));
return apiReadJobStatusNoCounts(tc,output,jobID);
}
else if (path.equals("outputconnections"))
{
return apiReadOutputConnections(tc,output);
}
else if (path.startsWith("outputconnections/"))
{
String connectionName = decodeAPIPathElement(path.substring("outputconnections/".length()));
return apiReadOutputConnection(tc,output,connectionName);
}
else if (path.equals("mappingconnections"))
{
return apiReadMappingConnections(tc,output);
}
else if (path.startsWith("mappingconnections/"))
{
String connectionName = decodeAPIPathElement(path.substring("mappingconnections/".length()));
return apiReadMappingConnection(tc,output,connectionName);
}
else if (path.equals("authorityconnections"))
{
return apiReadAuthorityConnections(tc,output);
}
else if (path.startsWith("authorityconnections/"))
{
String connectionName = decodeAPIPathElement(path.substring("authorityconnections/".length()));
return apiReadAuthorityConnection(tc,output,connectionName);
}
else if (path.equals("repositoryconnections"))
{
return apiReadRepositoryConnections(tc,output);
}
else if (path.startsWith("repositoryconnections/"))
{
String connectionName = decodeAPIPathElement(path.substring("repositoryconnections/".length()));
return apiReadRepositoryConnection(tc,output,connectionName);
}
else if (path.equals("outputconnectors"))
{
return apiReadOutputConnectors(tc,output);
}
else if (path.equals("mappingconnectors"))
{
return apiReadMappingConnectors(tc,output);
}
else if (path.equals("authorityconnectors"))
{
return apiReadAuthorityConnectors(tc,output);
}
else if (path.equals("repositoryconnectors"))
{
return apiReadRepositoryConnectors(tc,output);
}
else
{
createErrorNode(output,"Unrecognized resource.");
return READRESULT_NOTFOUND;
}
}
// Post result codes
public static final int POSTRESULT_NOTFOUND = 0;
public static final int POSTRESULT_FOUND = 1;
public static final int POSTRESULT_CREATED = 2;
/** Post job.
*/
protected static int apiPostJob(IThreadContext tc, Configuration output, Configuration input)
throws ManifoldCFException
{
ConfigurationNode jobNode = findConfigurationNode(input,API_JOBNODE);
if (jobNode == null)
throw new ManifoldCFException("Input must have '"+API_JOBNODE+"' field");
// Turn the configuration node into a JobDescription
org.apache.manifoldcf.crawler.jobs.JobDescription job = new org.apache.manifoldcf.crawler.jobs.JobDescription();
processJobDescription(job,jobNode);
if (job.getID() != null)
throw new ManifoldCFException("Input job cannot supply an ID field for create");
try
{
Long jobID = new Long(IDFactory.make(tc));
job.setID(jobID);
job.setIsNew(true);
// Save the job.
IJobManager jobManager = JobManagerFactory.make(tc);
jobManager.save(job);
ConfigurationNode idNode = new ConfigurationNode(API_JOBIDNODE);
idNode.setValue(jobID.toString());
output.addChild(output.getChildCount(),idNode);
return POSTRESULT_CREATED;
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return POSTRESULT_FOUND;
}
/** Execute specified post command.
*@param tc is the thread context.
*@param output is the output object, to be filled in.
*@param path is the object path.
*@param input is the input object.
*@return write result - either "not found", "found", or "created".
*/
public static int executePostCommand(IThreadContext tc, Configuration output, String path, Configuration input)
throws ManifoldCFException
{
if (path.equals("jobs"))
{
return apiPostJob(tc,output,input);
}
else
{
createErrorNode(output,"Unrecognized resource.");
return POSTRESULT_NOTFOUND;
}
}
// Write result codes
public static final int WRITERESULT_NOTFOUND = 0;
public static final int WRITERESULT_FOUND = 1;
public static final int WRITERESULT_CREATED = 2;
/** Start a job.
*/
protected static int apiWriteStartJob(IThreadContext tc, Configuration output, Long jobID, boolean requestMinimum)
throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
jobManager.manualStart(jobID,requestMinimum);
return WRITERESULT_CREATED;
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return WRITERESULT_FOUND;
}
/** Abort a job.
*/
protected static int apiWriteAbortJob(IThreadContext tc, Configuration output, Long jobID)
throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
jobManager.manualAbort(jobID);
return WRITERESULT_CREATED;
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return WRITERESULT_FOUND;
}
/** Restart a job.
*/
protected static int apiWriteRestartJob(IThreadContext tc, Configuration output, Long jobID, boolean requestMinimum)
throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
jobManager.manualAbortRestart(jobID,requestMinimum);
return WRITERESULT_CREATED;
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return WRITERESULT_FOUND;
}
/** Pause a job.
*/
protected static int apiWritePauseJob(IThreadContext tc, Configuration output, Long jobID)
throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
jobManager.pauseJob(jobID);
return WRITERESULT_CREATED;
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return WRITERESULT_FOUND;
}
/** Resume a job.
*/
protected static int apiWriteResumeJob(IThreadContext tc, Configuration output, Long jobID)
throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
jobManager.restartJob(jobID);
return WRITERESULT_CREATED;
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return WRITERESULT_FOUND;
}
/** Write job.
*/
protected static int apiWriteJob(IThreadContext tc, Configuration output, Configuration input, Long jobID)
throws ManifoldCFException
{
ConfigurationNode jobNode = findConfigurationNode(input,API_JOBNODE);
if (jobNode == null)
throw new ManifoldCFException("Input must have '"+API_JOBNODE+"' field");
// Turn the configuration node into a JobDescription
org.apache.manifoldcf.crawler.jobs.JobDescription job = new org.apache.manifoldcf.crawler.jobs.JobDescription();
processJobDescription(job,jobNode);
try
{
if (job.getID() == null)
{
job.setID(jobID);
}
else
{
if (!job.getID().equals(jobID))
throw new ManifoldCFException("Job identifier must agree within object and within path");
}
job.setIsNew(false);
// Save the job.
IJobManager jobManager = JobManagerFactory.make(tc);
jobManager.save(job);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return WRITERESULT_FOUND;
}
/** Write output connection.
*/
protected static int apiWriteOutputConnection(IThreadContext tc, Configuration output, Configuration input, String connectionName)
throws ManifoldCFException
{
ConfigurationNode connectionNode = findConfigurationNode(input,API_OUTPUTCONNECTIONNODE);
if (connectionNode == null)
throw new ManifoldCFException("Input argument must have '"+API_OUTPUTCONNECTIONNODE+"' field");
// Turn the configuration node into an OutputConnection
org.apache.manifoldcf.agents.outputconnection.OutputConnection outputConnection = new org.apache.manifoldcf.agents.outputconnection.OutputConnection();
processOutputConnection(outputConnection,connectionNode);
if (outputConnection.getName() == null)
outputConnection.setName(connectionName);
else
{
if (!outputConnection.getName().equals(connectionName))
throw new ManifoldCFException("Connection name in path and in object must agree");
}
try
{
// Save the connection.
IOutputConnectionManager connectionManager = OutputConnectionManagerFactory.make(tc);
if (connectionManager.save(outputConnection))
return WRITERESULT_CREATED;
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return WRITERESULT_FOUND;
}
/** Write authority connection.
*/
protected static int apiWriteAuthorityConnection(IThreadContext tc, Configuration output, Configuration input, String connectionName)
throws ManifoldCFException
{
ConfigurationNode connectionNode = findConfigurationNode(input,API_AUTHORITYCONNECTIONNODE);
if (connectionNode == null)
throw new ManifoldCFException("Input argument must have '"+API_AUTHORITYCONNECTIONNODE+"' field");
// Turn the configuration node into an OutputConnection
org.apache.manifoldcf.authorities.authority.AuthorityConnection authorityConnection = new org.apache.manifoldcf.authorities.authority.AuthorityConnection();
processAuthorityConnection(authorityConnection,connectionNode);
if (authorityConnection.getName() == null)
authorityConnection.setName(connectionName);
else
{
if (!authorityConnection.getName().equals(connectionName))
throw new ManifoldCFException("Connection name in path and in object must agree");
}
try
{
// Save the connection.
IAuthorityConnectionManager connectionManager = AuthorityConnectionManagerFactory.make(tc);
if (connectionManager.save(authorityConnection))
return WRITERESULT_CREATED;
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return WRITERESULT_FOUND;
}
/** Write mapping connection.
*/
protected static int apiWriteMappingConnection(IThreadContext tc, Configuration output, Configuration input, String connectionName)
throws ManifoldCFException
{
ConfigurationNode connectionNode = findConfigurationNode(input,API_MAPPINGCONNECTIONNODE);
if (connectionNode == null)
throw new ManifoldCFException("Input argument must have '"+API_MAPPINGCONNECTIONNODE+"' field");
// Turn the configuration node into an OutputConnection
org.apache.manifoldcf.authorities.mapping.MappingConnection mappingConnection = new org.apache.manifoldcf.authorities.mapping.MappingConnection();
processMappingConnection(mappingConnection,connectionNode);
if (mappingConnection.getName() == null)
mappingConnection.setName(connectionName);
else
{
if (!mappingConnection.getName().equals(connectionName))
throw new ManifoldCFException("Connection name in path and in object must agree");
}
try
{
// Save the connection.
IMappingConnectionManager connectionManager = MappingConnectionManagerFactory.make(tc);
if (connectionManager.save(mappingConnection))
return WRITERESULT_CREATED;
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return WRITERESULT_FOUND;
}
/** Write repository connection.
*/
protected static int apiWriteRepositoryConnection(IThreadContext tc, Configuration output, Configuration input, String connectionName)
throws ManifoldCFException
{
ConfigurationNode connectionNode = findConfigurationNode(input,API_REPOSITORYCONNECTIONNODE);
if (connectionNode == null)
throw new ManifoldCFException("Input argument must have '"+API_REPOSITORYCONNECTIONNODE+"' field");
// Turn the configuration node into an OutputConnection
org.apache.manifoldcf.crawler.repository.RepositoryConnection repositoryConnection = new org.apache.manifoldcf.crawler.repository.RepositoryConnection();
processRepositoryConnection(repositoryConnection,connectionNode);
if (repositoryConnection.getName() == null)
repositoryConnection.setName(connectionName);
else
{
if (!repositoryConnection.getName().equals(connectionName))
throw new ManifoldCFException("Connection name in path and in object must agree");
}
try
{
// Save the connection.
IRepositoryConnectionManager connectionManager = RepositoryConnectionManagerFactory.make(tc);
if (connectionManager.save(repositoryConnection))
return WRITERESULT_CREATED;
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return WRITERESULT_FOUND;
}
/** Reset output connection.
*/
protected static int apiWriteResetOutputConnection(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
signalOutputConnectionRedo(tc,connectionName);
return WRITERESULT_CREATED;
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return WRITERESULT_FOUND;
}
/** Execute specified write command.
*@param tc is the thread context.
*@param output is the output object, to be filled in.
*@param path is the object path.
*@param input is the input object.
*@return write result - either "not found", "found", or "created".
*/
public static int executeWriteCommand(IThreadContext tc, Configuration output, String path, Configuration input)
throws ManifoldCFException
{
if (path.startsWith("start/"))
{
Long jobID = new Long(path.substring("start/".length()));
return apiWriteStartJob(tc,output,jobID,false);
}
else if (path.startsWith("startminimal/"))
{
Long jobID = new Long(path.substring("startminimal/".length()));
return apiWriteStartJob(tc,output,jobID,true);
}
else if (path.startsWith("abort/"))
{
Long jobID = new Long(path.substring("abort/".length()));
return apiWriteAbortJob(tc,output,jobID);
}
else if (path.startsWith("restart/"))
{
Long jobID = new Long(path.substring("restart/".length()));
return apiWriteRestartJob(tc,output,jobID,false);
}
else if (path.startsWith("restartminimal/"))
{
Long jobID = new Long(path.substring("restartminimal/".length()));
return apiWriteRestartJob(tc,output,jobID,true);
}
else if (path.startsWith("pause/"))
{
Long jobID = new Long(path.substring("pause/".length()));
return apiWritePauseJob(tc,output,jobID);
}
else if (path.startsWith("resume/"))
{
Long jobID = new Long(path.substring("resume/".length()));
return apiWriteResumeJob(tc,output,jobID);
}
else if (path.startsWith("jobs/"))
{
Long jobID = new Long(path.substring("jobs/".length()));
return apiWriteJob(tc,output,input,jobID);
}
else if (path.startsWith("outputconnections/"))
{
String connectionName = decodeAPIPathElement(path.substring("outputconnections/".length()));
return apiWriteOutputConnection(tc,output,input,connectionName);
}
else if (path.startsWith("mappingconnections/"))
{
String connectionName = decodeAPIPathElement(path.substring("mappingconnections/".length()));
return apiWriteMappingConnection(tc,output,input,connectionName);
}
else if (path.startsWith("authorityconnections/"))
{
String connectionName = decodeAPIPathElement(path.substring("authorityconnections/".length()));
return apiWriteAuthorityConnection(tc,output,input,connectionName);
}
else if (path.startsWith("repositoryconnections/"))
{
String connectionName = decodeAPIPathElement(path.substring("repositoryconnections/".length()));
return apiWriteRepositoryConnection(tc,output,input,connectionName);
}
else if (path.startsWith("reset/"))
{
int firstSeparator = "reset/".length();
int secondSeparator = path.indexOf("/",firstSeparator);
if (secondSeparator == -1)
{
createErrorNode(output,"Need connection name.");
return WRITERESULT_NOTFOUND;
}
String connectionType = path.substring(firstSeparator,secondSeparator);
String connectionName = decodeAPIPathElement(path.substring(secondSeparator+1));
if (connectionType.equals("outputconnections"))
{
return apiWriteResetOutputConnection(tc,output,connectionName);
}
else
{
createErrorNode(output,"Unknown connection type '"+connectionType+"'.");
return WRITERESULT_NOTFOUND;
}
}
else
{
createErrorNode(output,"Unrecognized resource.");
return WRITERESULT_NOTFOUND;
}
}
// Delete result codes
public static final int DELETERESULT_NOTFOUND = 0;
public static final int DELETERESULT_FOUND = 1;
/** Delete a job.
*/
protected static int apiDeleteJob(IThreadContext tc, Configuration output, Long jobID)
throws ManifoldCFException
{
try
{
IJobManager jobManager = JobManagerFactory.make(tc);
jobManager.deleteJob(jobID);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return DELETERESULT_FOUND;
}
/** Delete output connection.
*/
protected static int apiDeleteOutputConnection(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
IOutputConnectionManager connectionManager = OutputConnectionManagerFactory.make(tc);
connectionManager.delete(connectionName);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return DELETERESULT_FOUND;
}
/** Delete authority connection.
*/
protected static int apiDeleteAuthorityConnection(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
IAuthorityConnectionManager connectionManager = AuthorityConnectionManagerFactory.make(tc);
connectionManager.delete(connectionName);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return DELETERESULT_FOUND;
}
/** Delete repository connection.
*/
protected static int apiDeleteRepositoryConnection(IThreadContext tc, Configuration output, String connectionName)
throws ManifoldCFException
{
try
{
IRepositoryConnectionManager connectionManager = RepositoryConnectionManagerFactory.make(tc);
connectionManager.delete(connectionName);
}
catch (ManifoldCFException e)
{
createErrorNode(output,e);
}
return DELETERESULT_FOUND;
}
/** Execute specified delete command.
*@param tc is the thread context.
*@param output is the output object, to be filled in.
*@param path is the object path.
*@return delete result code
*/
public static int executeDeleteCommand(IThreadContext tc, Configuration output, String path)
throws ManifoldCFException
{
if (path.startsWith("jobs/"))
{
Long jobID = new Long(path.substring("jobs/".length()));
return apiDeleteJob(tc,output,jobID);
}
else if (path.startsWith("outputconnections/"))
{
String connectionName = decodeAPIPathElement(path.substring("outputconnections/".length()));
return apiDeleteOutputConnection(tc,output,connectionName);
}
else if (path.startsWith("authorityconnections/"))
{
String connectionName = decodeAPIPathElement(path.substring("authorityconnections/".length()));
return apiDeleteAuthorityConnection(tc,output,connectionName);
}
else if (path.startsWith("repositoryconnections/"))
{
String connectionName = decodeAPIPathElement(path.substring("repositoryconnections/".length()));
return apiDeleteRepositoryConnection(tc,output,connectionName);
}
else
{
createErrorNode(output,"Unrecognized resource.");
return DELETERESULT_NOTFOUND;
}
}
// The following chunk of code is responsible for formatting a job description into a set of nodes, and for reading back a formatted job description.
// This is needed to support the job-related API methods, above.
// Job node types
protected static final String JOBNODE_ID = "id";
protected static final String JOBNODE_DESCRIPTION = "description";
protected static final String JOBNODE_CONNECTIONNAME = "repository_connection";
protected static final String JOBNODE_OUTPUTNAME = "output_connection";
protected static final String JOBNODE_DOCUMENTSPECIFICATION = "document_specification";
protected static final String JOBNODE_OUTPUTSPECIFICATION = "output_specification";
protected static final String JOBNODE_STARTMODE = "start_mode";
protected static final String JOBNODE_RUNMODE = "run_mode";
protected static final String JOBNODE_HOPCOUNTMODE = "hopcount_mode";
protected static final String JOBNODE_PRIORITY = "priority";
protected static final String JOBNODE_RECRAWLINTERVAL = "recrawl_interval";
protected static final String JOBNODE_EXPIRATIONINTERVAL = "expiration_interval";
protected static final String JOBNODE_RESEEDINTERVAL = "reseed_interval";
protected static final String JOBNODE_HOPCOUNT = "hopcount";
protected static final String JOBNODE_SCHEDULE = "schedule";
protected static final String JOBNODE_LINKTYPE = "link_type";
protected static final String JOBNODE_COUNT = "count";
protected static final String JOBNODE_REQUESTMINIMUM = "requestminimum";
protected static final String JOBNODE_TIMEZONE = "timezone";
protected static final String JOBNODE_DURATION = "duration";
protected static final String JOBNODE_DAYOFWEEK = "dayofweek";
protected static final String JOBNODE_MONTHOFYEAR = "monthofyear";
protected static final String JOBNODE_DAYOFMONTH = "dayofmonth";
protected static final String JOBNODE_YEAR = "year";
protected static final String JOBNODE_HOUROFDAY = "hourofday";
protected static final String JOBNODE_MINUTESOFHOUR = "minutesofhour";
protected static final String JOBNODE_ENUMVALUE = "value";
protected static final String JOBNODE_FORCEDPARAM = "forcedparam";
protected static final String JOBNODE_PARAMNAME = "paramname";
protected static final String JOBNODE_PARAMVALUE = "paramvalue";
/** Convert a node into a job description.
*@param jobDescription is the job to be filled in.
*@param jobNode is the configuration node corresponding to the whole job itself.
*/
protected static void processJobDescription(org.apache.manifoldcf.crawler.jobs.JobDescription jobDescription, ConfigurationNode jobNode)
throws ManifoldCFException
{
// Walk through the node's children
int i = 0;
while (i < jobNode.getChildCount())
{
ConfigurationNode child = jobNode.findChild(i++);
String childType = child.getType();
if (childType.equals(JOBNODE_ID))
{
if (child.getValue() == null)
throw new ManifoldCFException("Job id node requires a value");
jobDescription.setID(new Long(child.getValue()));
}
else if (childType.equals(JOBNODE_DESCRIPTION))
{
jobDescription.setDescription(child.getValue());
}
else if (childType.equals(JOBNODE_CONNECTIONNAME))
{
jobDescription.setConnectionName(child.getValue());
}
else if (childType.equals(JOBNODE_OUTPUTNAME))
{
jobDescription.setOutputConnectionName(child.getValue());
}
else if (childType.equals(JOBNODE_DOCUMENTSPECIFICATION))
{
// Get the job's document specification, clear out the children, and copy new ones from the child.
DocumentSpecification ds = jobDescription.getSpecification();
ds.clearChildren();
int j = 0;
while (j < child.getChildCount())
{
ConfigurationNode cn = child.findChild(j++);
ds.addChild(ds.getChildCount(),new SpecificationNode(cn));
}
}
else if (childType.equals(JOBNODE_OUTPUTSPECIFICATION))
{
// Get the job's output specification, clear out the children, and copy new ones from the child.
OutputSpecification os = jobDescription.getOutputSpecification();
os.clearChildren();
int j = 0;
while (j < child.getChildCount())
{
ConfigurationNode cn = child.findChild(j++);
os.addChild(os.getChildCount(),new SpecificationNode(cn));
}
}
else if (childType.equals(JOBNODE_STARTMODE))
{
jobDescription.setStartMethod(mapToStartMode(child.getValue()));
}
else if (childType.equals(JOBNODE_RUNMODE))
{
jobDescription.setType(mapToRunMode(child.getValue()));
}
else if (childType.equals(JOBNODE_HOPCOUNTMODE))
{
jobDescription.setHopcountMode(mapToHopcountMode(child.getValue()));
}
else if (childType.equals(JOBNODE_PRIORITY))
{
try
{
jobDescription.setPriority(Integer.parseInt(child.getValue()));
}
catch (NumberFormatException e)
{
throw new ManifoldCFException(e.getMessage(),e);
}
}
else if (childType.equals(JOBNODE_RECRAWLINTERVAL))
{
jobDescription.setInterval(interpretInterval(child.getValue()));
}
else if (childType.equals(JOBNODE_EXPIRATIONINTERVAL))
{
jobDescription.setExpiration(interpretInterval(child.getValue()));
}
else if (childType.equals(JOBNODE_RESEEDINTERVAL))
{
jobDescription.setReseedInterval(interpretInterval(child.getValue()));
}
else if (childType.equals(JOBNODE_HOPCOUNT))
{
// Read the hopcount values
String linkType = null;
String hopCount = null;
int q = 0;
while (q < child.getChildCount())
{
ConfigurationNode cn = child.findChild(q++);
if (cn.getType().equals(JOBNODE_LINKTYPE))
linkType = cn.getValue();
else if (cn.getType().equals(JOBNODE_COUNT))
hopCount = cn.getValue();
else
throw new ManifoldCFException("Found an unexpected node type: '"+cn.getType()+"'");
}
if (linkType == null)
throw new ManifoldCFException("Missing required field: '"+JOBNODE_LINKTYPE+"'");
if (hopCount == null)
throw new ManifoldCFException("Missing required field: '"+JOBNODE_COUNT+"'");
jobDescription.addHopCountFilter(linkType,new Long(hopCount));
}
else if (childType.equals(JOBNODE_FORCEDPARAM))
{
// Read the forced parameter values
String paramName = null;
String paramValue = null;
for (int q = 0; q < child.getChildCount(); q++)
{
ConfigurationNode cn = child.findChild(q);
if (cn.getType().equals(JOBNODE_PARAMNAME))
paramName = cn.getValue();
else if (cn.getType().equals(JOBNODE_PARAMVALUE))
paramValue = cn.getValue();
else
throw new ManifoldCFException("Found an unexpected node type: '"+cn.getType()+"'");
}
if (paramName == null)
throw new ManifoldCFException("Missing required field: '"+JOBNODE_PARAMNAME+"'");
if (paramValue == null)
throw new ManifoldCFException("Missing required field: '"+JOBNODE_PARAMVALUE+"'");
jobDescription.addForcedMetadataValue(paramName,paramValue);
}
else if (childType.equals(JOBNODE_SCHEDULE))
{
// Create a schedule record.
String timezone = null;
Long duration = null;
boolean requestMinimum = false;
EnumeratedValues dayOfWeek = null;
EnumeratedValues monthOfYear = null;
EnumeratedValues dayOfMonth = null;
EnumeratedValues year = null;
EnumeratedValues hourOfDay = null;
EnumeratedValues minutesOfHour = null;
// Now, walk through children of the schedule node.
int q = 0;
while (q < child.getChildCount())
{
ConfigurationNode scheduleField = child.findChild(q++);
String fieldType = scheduleField.getType();
if (fieldType.equals(JOBNODE_REQUESTMINIMUM))
{
requestMinimum = scheduleField.getValue().equals("true");
}
if (fieldType.equals(JOBNODE_TIMEZONE))
{
timezone = scheduleField.getValue();
}
else if (fieldType.equals(JOBNODE_DURATION))
{
duration = new Long(scheduleField.getValue());
}
else if (fieldType.equals(JOBNODE_DAYOFWEEK))
{
dayOfWeek = processEnumeratedValues(scheduleField);
}
else if (fieldType.equals(JOBNODE_MONTHOFYEAR))
{
monthOfYear = processEnumeratedValues(scheduleField);
}
else if (fieldType.equals(JOBNODE_YEAR))
{
year = processEnumeratedValues(scheduleField);
}
else if (fieldType.equals(JOBNODE_DAYOFMONTH))
{
dayOfMonth = processEnumeratedValues(scheduleField);
}
else if (fieldType.equals(JOBNODE_HOUROFDAY))
{
hourOfDay = processEnumeratedValues(scheduleField);
}
else if (fieldType.equals(JOBNODE_MINUTESOFHOUR))
{
minutesOfHour = processEnumeratedValues(scheduleField);
}
else
throw new ManifoldCFException("Unrecognized field in schedule record: '"+fieldType+"'");
}
ScheduleRecord sr = new ScheduleRecord(dayOfWeek,monthOfYear,dayOfMonth,year,hourOfDay,minutesOfHour,timezone,duration,requestMinimum);
// Add the schedule record to the job.
jobDescription.addScheduleRecord(sr);
}
else
throw new ManifoldCFException("Unrecognized job field: '"+childType+"'");
}
}
/** Convert a job description into a ConfigurationNode.
*@param jobNode is the node to be filled in.
*@param job is the job description.
*/
protected static void formatJobDescription(ConfigurationNode jobNode, IJobDescription job)
{
// For each field of the job, add an appropriate child node, with value.
ConfigurationNode child;
int j;
// id
if (job.getID() != null)
{
child = new ConfigurationNode(JOBNODE_ID);
child.setValue(job.getID().toString());
jobNode.addChild(jobNode.getChildCount(),child);
}
// description
if (job.getDescription() != null)
{
child = new ConfigurationNode(JOBNODE_DESCRIPTION);
child.setValue(job.getDescription());
jobNode.addChild(jobNode.getChildCount(),child);
}
// connection
if (job.getConnectionName() != null)
{
child = new ConfigurationNode(JOBNODE_CONNECTIONNAME);
child.setValue(job.getConnectionName());
jobNode.addChild(jobNode.getChildCount(),child);
}
// output connection
if (job.getOutputConnectionName() != null)
{
child = new ConfigurationNode(JOBNODE_OUTPUTNAME);
child.setValue(job.getOutputConnectionName());
jobNode.addChild(jobNode.getChildCount(),child);
}
// Document specification
DocumentSpecification ds = job.getSpecification();
child = new ConfigurationNode(JOBNODE_DOCUMENTSPECIFICATION);
j = 0;
while (j < ds.getChildCount())
{
ConfigurationNode cn = ds.getChild(j++);
child.addChild(child.getChildCount(),cn);
}
jobNode.addChild(jobNode.getChildCount(),child);
// Output specification
OutputSpecification os = job.getOutputSpecification();
child = new ConfigurationNode(JOBNODE_OUTPUTSPECIFICATION);
j = 0;
while (j < os.getChildCount())
{
ConfigurationNode cn = os.getChild(j++);
child.addChild(child.getChildCount(),cn);
}
jobNode.addChild(jobNode.getChildCount(),child);
// Start mode
child = new ConfigurationNode(JOBNODE_STARTMODE);
child.setValue(startModeMap(job.getStartMethod()));
jobNode.addChild(jobNode.getChildCount(),child);
// Run mode
child = new ConfigurationNode(JOBNODE_RUNMODE);
child.setValue(runModeMap(job.getType()));
jobNode.addChild(jobNode.getChildCount(),child);
// Hopcount mode
child = new ConfigurationNode(JOBNODE_HOPCOUNTMODE);
child.setValue(hopcountModeMap(job.getHopcountMode()));
jobNode.addChild(jobNode.getChildCount(),child);
// Priority
child = new ConfigurationNode(JOBNODE_PRIORITY);
child.setValue(Integer.toString(job.getPriority()));
jobNode.addChild(jobNode.getChildCount(),child);
// Recrawl interval
child = new ConfigurationNode(JOBNODE_RECRAWLINTERVAL);
child.setValue((job.getInterval()==null)?"infinite":job.getInterval().toString());
jobNode.addChild(jobNode.getChildCount(),child);
child = new ConfigurationNode(JOBNODE_EXPIRATIONINTERVAL);
child.setValue((job.getExpiration()==null)?"infinite":job.getExpiration().toString());
jobNode.addChild(jobNode.getChildCount(),child);
child = new ConfigurationNode(JOBNODE_RESEEDINTERVAL);
child.setValue((job.getReseedInterval()==null)?"infinite":job.getReseedInterval().toString());
jobNode.addChild(jobNode.getChildCount(),child);
// Hopcount records
Map filters = job.getHopCountFilters();
Iterator iter = filters.keySet().iterator();
while (iter.hasNext())
{
String linkType = (String)iter.next();
Long hopCount = (Long)filters.get(linkType);
child = new ConfigurationNode(JOBNODE_HOPCOUNT);
ConfigurationNode cn;
cn = new ConfigurationNode(JOBNODE_LINKTYPE);
cn.setValue(linkType);
child.addChild(child.getChildCount(),cn);
cn = new ConfigurationNode(JOBNODE_COUNT);
cn.setValue(hopCount.toString());
child.addChild(child.getChildCount(),cn);
jobNode.addChild(jobNode.getChildCount(),child);
}
// Forced metadata records
Map<String,Set<String>> forcedMetadata = job.getForcedMetadata();
for (String paramName : forcedMetadata.keySet())
{
Set<String> values = forcedMetadata.get(paramName);
for (String paramValue : values)
{
child = new ConfigurationNode(JOBNODE_FORCEDPARAM);
ConfigurationNode cn;
cn = new ConfigurationNode(JOBNODE_PARAMNAME);
cn.setValue(paramName);
child.addChild(child.getChildCount(),cn);
cn = new ConfigurationNode(JOBNODE_PARAMVALUE);
cn.setValue(paramValue);
child.addChild(child.getChildCount(),cn);
jobNode.addChild(jobNode.getChildCount(),child);
}
}
// Schedule records
j = 0;
while (j < job.getScheduleRecordCount())
{
ScheduleRecord sr = job.getScheduleRecord(j++);
child = new ConfigurationNode(JOBNODE_SCHEDULE);
ConfigurationNode recordChild;
// requestminimum
recordChild = new ConfigurationNode(JOBNODE_REQUESTMINIMUM);
recordChild.setValue(sr.getRequestMinimum()?"true":"false");
child.addChild(child.getChildCount(),recordChild);
// timezone
if (sr.getTimezone() != null)
{
recordChild = new ConfigurationNode(JOBNODE_TIMEZONE);
recordChild.setValue(sr.getTimezone());
child.addChild(child.getChildCount(),recordChild);
}
// duration
if (sr.getDuration() != null)
{
recordChild = new ConfigurationNode(JOBNODE_DURATION);
recordChild.setValue(sr.getDuration().toString());
child.addChild(child.getChildCount(),recordChild);
}
// Schedule specification values
// day of week
if (sr.getDayOfWeek() != null)
formatEnumeratedValues(child,JOBNODE_DAYOFWEEK,sr.getDayOfWeek());
if (sr.getMonthOfYear() != null)
formatEnumeratedValues(child,JOBNODE_MONTHOFYEAR,sr.getMonthOfYear());
if (sr.getDayOfMonth() != null)
formatEnumeratedValues(child,JOBNODE_DAYOFMONTH,sr.getDayOfMonth());
if (sr.getYear() != null)
formatEnumeratedValues(child,JOBNODE_YEAR,sr.getYear());
if (sr.getHourOfDay() != null)
formatEnumeratedValues(child,JOBNODE_HOUROFDAY,sr.getHourOfDay());
if (sr.getMinutesOfHour() != null)
formatEnumeratedValues(child,JOBNODE_MINUTESOFHOUR,sr.getMinutesOfHour());
jobNode.addChild(jobNode.getChildCount(),child);
}
}
protected static void formatEnumeratedValues(ConfigurationNode recordNode, String childType, EnumeratedValues value)
{
ConfigurationNode child = new ConfigurationNode(childType);
Iterator iter = value.getValues();
while (iter.hasNext())
{
Integer theValue = (Integer)iter.next();
ConfigurationNode valueNode = new ConfigurationNode(JOBNODE_ENUMVALUE);
valueNode.setValue(theValue.toString());
child.addChild(child.getChildCount(),valueNode);
}
recordNode.addChild(recordNode.getChildCount(),child);
}
protected static EnumeratedValues processEnumeratedValues(ConfigurationNode fieldNode)
throws ManifoldCFException
{
ArrayList values = new ArrayList();
int i = 0;
while (i < fieldNode.getChildCount())
{
ConfigurationNode cn = fieldNode.findChild(i++);
if (cn.getType().equals(JOBNODE_ENUMVALUE))
{
try
{
values.add(new Integer(cn.getValue()));
}
catch (NumberFormatException e)
{
throw new ManifoldCFException("Error processing enumerated value node: "+e.getMessage(),e);
}
}
else
throw new ManifoldCFException("Error processing enumerated value nodes: Unrecognized node type '"+cn.getType()+"'");
}
return new EnumeratedValues(values);
}
protected static String presentInterval(Long interval)
{
if (interval == null)
return "infinite";
return interval.toString();
}
protected static Long interpretInterval(String interval)
throws ManifoldCFException
{
if (interval == null || interval.equals("infinite"))
return null;
else
return new Long(interval);
}
protected static String startModeMap(int startMethod)
{
switch (startMethod)
{
case IJobDescription.START_WINDOWBEGIN:
return "schedule window start";
case IJobDescription.START_WINDOWINSIDE:
return "schedule window anytime";
case IJobDescription.START_DISABLE:
return "manual";
default:
return "unknown";
}
}
protected static int mapToStartMode(String startMethod)
throws ManifoldCFException
{
if (startMethod.equals("schedule window start"))
return IJobDescription.START_WINDOWBEGIN;
else if (startMethod.equals("schedule window anytime"))
return IJobDescription.START_WINDOWINSIDE;
else if (startMethod.equals("manual"))
return IJobDescription.START_DISABLE;
else
throw new ManifoldCFException("Unrecognized start method: '"+startMethod+"'");
}
protected static String runModeMap(int type)
{
switch (type)
{
case IJobDescription.TYPE_CONTINUOUS:
return "continuous";
case IJobDescription.TYPE_SPECIFIED:
return "scan once";
default:
return "unknown";
}
}
protected static int mapToRunMode(String mode)
throws ManifoldCFException
{
if (mode.equals("continuous"))
return IJobDescription.TYPE_CONTINUOUS;
else if (mode.equals("scan once"))
return IJobDescription.TYPE_SPECIFIED;
else
throw new ManifoldCFException("Unrecognized run method: '"+mode+"'");
}
protected static String hopcountModeMap(int mode)
{
switch (mode)
{
case IJobDescription.HOPCOUNT_ACCURATE:
return "accurate";
case IJobDescription.HOPCOUNT_NODELETE:
return "no delete";
case IJobDescription.HOPCOUNT_NEVERDELETE:
return "never delete";
default:
return "unknown";
}
}
protected static int mapToHopcountMode(String mode)
throws ManifoldCFException
{
if (mode.equals("accurate"))
return IJobDescription.HOPCOUNT_ACCURATE;
else if (mode.equals("no delete"))
return IJobDescription.HOPCOUNT_NODELETE;
else if (mode.equals("never delete"))
return IJobDescription.HOPCOUNT_NEVERDELETE;
else
throw new ManifoldCFException("Unrecognized hopcount method: '"+mode+"'");
}
// End of job API support code.
// The following chunk of code supports job statuses in the API. Only a formatting method is required, since we never "save" a status.
// Node types used to handle job statuses.
protected static final String JOBSTATUSNODE_JOBID = "job_id";
protected static final String JOBSTATUSNODE_STATUS = "status";
protected static final String JOBSTATUSNODE_ERRORTEXT = "errortext";
protected static final String JOBSTATUSNODE_STARTTIME = "start_time";
protected static final String JOBSTATUSNODE_ENDTIME = "end_time";
protected static final String JOBSTATUSNODE_DOCUMENTSINQUEUE = "documents_in_queue";
protected static final String JOBSTATUSNODE_DOCUMENTSOUTSTANDING = "documents_outstanding";
protected static final String JOBSTATUSNODE_DOCUMENTSPROCESSED = "documents_processed";
/** Format a job status.
*/
protected static void formatJobStatus(ConfigurationNode jobStatusNode, JobStatus jobStatus)
{
// For each field of the job, add an appropriate child node, with value.
ConfigurationNode child;
int j;
// id
child = new ConfigurationNode(JOBSTATUSNODE_JOBID);
child.setValue(jobStatus.getJobID().toString());
jobStatusNode.addChild(jobStatusNode.getChildCount(),child);
// status
child = new ConfigurationNode(JOBSTATUSNODE_STATUS);
child.setValue(statusMap(jobStatus.getStatus()));
jobStatusNode.addChild(jobStatusNode.getChildCount(),child);
// error text
if (jobStatus.getErrorText() != null)
{
child = new ConfigurationNode(JOBSTATUSNODE_ERRORTEXT);
child.setValue(jobStatus.getErrorText());
jobStatusNode.addChild(jobStatusNode.getChildCount(),child);
}
// start time
if (jobStatus.getStartTime() != -1L)
{
child = new ConfigurationNode(JOBSTATUSNODE_STARTTIME);
child.setValue(new Long(jobStatus.getStartTime()).toString());
jobStatusNode.addChild(jobStatusNode.getChildCount(),child);
}
// end time
if (jobStatus.getEndTime() != -1L)
{
child = new ConfigurationNode(JOBSTATUSNODE_ENDTIME);
child.setValue(new Long(jobStatus.getEndTime()).toString());
jobStatusNode.addChild(jobStatusNode.getChildCount(),child);
}
// documents in queue
child = new ConfigurationNode(JOBSTATUSNODE_DOCUMENTSINQUEUE);
child.setValue(new Long(jobStatus.getDocumentsInQueue()).toString());
jobStatusNode.addChild(jobStatusNode.getChildCount(),child);
// documents outstanding
child = new ConfigurationNode(JOBSTATUSNODE_DOCUMENTSOUTSTANDING);
child.setValue(new Long(jobStatus.getDocumentsOutstanding()).toString());
jobStatusNode.addChild(jobStatusNode.getChildCount(),child);
// documents processed
child = new ConfigurationNode(JOBSTATUSNODE_DOCUMENTSPROCESSED);
child.setValue(new Long(jobStatus.getDocumentsProcessed()).toString());
jobStatusNode.addChild(jobStatusNode.getChildCount(),child);
}
protected static String statusMap(int status)
{
switch (status)
{
case JobStatus.JOBSTATUS_NOTYETRUN:
return "not yet run";
case JobStatus.JOBSTATUS_RUNNING:
return "running";
case JobStatus.JOBSTATUS_STOPPING:
return "stopping";
case JobStatus.JOBSTATUS_RESUMING:
return "resuming";
case JobStatus.JOBSTATUS_PAUSED:
return "paused";
case JobStatus.JOBSTATUS_COMPLETED:
return "done";
case JobStatus.JOBSTATUS_WINDOWWAIT:
return "waiting";
case JobStatus.JOBSTATUS_STARTING:
return "starting up";
case JobStatus.JOBSTATUS_DESTRUCTING:
return "cleaning up";
case JobStatus.JOBSTATUS_ERROR:
return "error";
case JobStatus.JOBSTATUS_ABORTING:
return "aborting";
case JobStatus.JOBSTATUS_RESTARTING:
return "restarting";
case JobStatus.JOBSTATUS_RUNNING_UNINSTALLED:
return "running no connector";
case JobStatus.JOBSTATUS_JOBENDCLEANUP:
return "terminating";
case JobStatus.JOBSTATUS_JOBENDNOTIFICATION:
return "notifying";
default:
return "unknown";
}
}
// End of jobstatus API support.
// Connection API
protected static final String CONNECTIONNODE_ISNEW = "isnew";
protected static final String CONNECTIONNODE_NAME = "name";
protected static final String CONNECTIONNODE_CLASSNAME = "class_name";
protected static final String CONNECTIONNODE_MAXCONNECTIONS = "max_connections";
protected static final String CONNECTIONNODE_DESCRIPTION = "description";
protected static final String CONNECTIONNODE_PREREQUISITE = "prerequisite";
protected static final String CONNECTIONNODE_CONFIGURATION = "configuration";
protected static final String CONNECTIONNODE_ACLAUTHORITY = "acl_authority";
protected static final String CONNECTIONNODE_THROTTLE = "throttle";
protected static final String CONNECTIONNODE_MATCH = "match";
protected static final String CONNECTIONNODE_MATCHDESCRIPTION = "match_description";
protected static final String CONNECTIONNODE_RATE = "rate";
// Output connection API support.
/** Convert input hierarchy into an OutputConnection object.
*/
protected static void processOutputConnection(org.apache.manifoldcf.agents.outputconnection.OutputConnection connection, ConfigurationNode connectionNode)
throws ManifoldCFException
{
// Walk through the node's children
int i = 0;
while (i < connectionNode.getChildCount())
{
ConfigurationNode child = connectionNode.findChild(i++);
String childType = child.getType();
if (childType.equals(CONNECTIONNODE_ISNEW))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection isnew node requires a value");
connection.setIsNew(child.getValue().equals("true"));
}
else if (childType.equals(CONNECTIONNODE_NAME))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection name node requires a value");
connection.setName(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_CLASSNAME))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection classname node requires a value");
connection.setClassName(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_MAXCONNECTIONS))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection maxconnections node requires a value");
try
{
connection.setMaxConnections(Integer.parseInt(child.getValue()));
}
catch (NumberFormatException e)
{
throw new ManifoldCFException("Error parsing max connections: "+e.getMessage(),e);
}
}
else if (childType.equals(CONNECTIONNODE_DESCRIPTION))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection description node requires a value");
connection.setDescription(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_CONFIGURATION))
{
// Get the connection's configuration, clear out the children, and copy new ones from the child.
ConfigParams cp = connection.getConfigParams();
cp.clearChildren();
int j = 0;
while (j < child.getChildCount())
{
ConfigurationNode cn = child.findChild(j++);
cp.addChild(cp.getChildCount(),new ConfigNode(cn));
}
}
else
throw new ManifoldCFException("Unrecognized output connection field: '"+childType+"'");
}
if (connection.getClassName() == null)
throw new ManifoldCFException("Missing connection field: '"+CONNECTIONNODE_CLASSNAME+"'");
}
/** Format an output connection.
*/
protected static void formatOutputConnection(ConfigurationNode connectionNode, IOutputConnection connection)
{
ConfigurationNode child;
int j;
child = new ConfigurationNode(CONNECTIONNODE_ISNEW);
child.setValue(connection.getIsNew()?"true":"false");
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_NAME);
child.setValue(connection.getName());
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_CLASSNAME);
child.setValue(connection.getClassName());
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_MAXCONNECTIONS);
child.setValue(Integer.toString(connection.getMaxConnections()));
connectionNode.addChild(connectionNode.getChildCount(),child);
if (connection.getDescription() != null)
{
child = new ConfigurationNode(CONNECTIONNODE_DESCRIPTION);
child.setValue(connection.getDescription());
connectionNode.addChild(connectionNode.getChildCount(),child);
}
ConfigParams cp = connection.getConfigParams();
child = new ConfigurationNode(CONNECTIONNODE_CONFIGURATION);
j = 0;
while (j < cp.getChildCount())
{
ConfigurationNode cn = cp.findChild(j++);
child.addChild(child.getChildCount(),cn);
}
connectionNode.addChild(connectionNode.getChildCount(),child);
}
// Authority connection API support
/** Convert input hierarchy into an AuthorityConnection object.
*/
protected static void processAuthorityConnection(org.apache.manifoldcf.authorities.authority.AuthorityConnection connection, ConfigurationNode connectionNode)
throws ManifoldCFException
{
// Walk through the node's children
int i = 0;
while (i < connectionNode.getChildCount())
{
ConfigurationNode child = connectionNode.findChild(i++);
String childType = child.getType();
if (childType.equals(CONNECTIONNODE_ISNEW))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection isnew node requires a value");
connection.setIsNew(child.getValue().equals("true"));
}
else if (childType.equals(CONNECTIONNODE_NAME))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection name node requires a value");
connection.setName(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_CLASSNAME))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection classname node requires a value");
connection.setClassName(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_MAXCONNECTIONS))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection maxconnections node requires a value");
try
{
connection.setMaxConnections(Integer.parseInt(child.getValue()));
}
catch (NumberFormatException e)
{
throw new ManifoldCFException("Error parsing max connections: "+e.getMessage(),e);
}
}
else if (childType.equals(CONNECTIONNODE_PREREQUISITE))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection prerequisite node requires a value");
connection.setPrerequisiteMapping(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_DESCRIPTION))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection description node requires a value");
connection.setDescription(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_CONFIGURATION))
{
// Get the connection's configuration, clear out the children, and copy new ones from the child.
ConfigParams cp = connection.getConfigParams();
cp.clearChildren();
int j = 0;
while (j < child.getChildCount())
{
ConfigurationNode cn = child.findChild(j++);
cp.addChild(cp.getChildCount(),new ConfigNode(cn));
}
}
else
throw new ManifoldCFException("Unrecognized authority connection field: '"+childType+"'");
}
if (connection.getClassName() == null)
throw new ManifoldCFException("Missing connection field: '"+CONNECTIONNODE_CLASSNAME+"'");
}
/** Format an authority connection.
*/
protected static void formatAuthorityConnection(ConfigurationNode connectionNode, IAuthorityConnection connection)
{
ConfigurationNode child;
int j;
child = new ConfigurationNode(CONNECTIONNODE_ISNEW);
child.setValue(connection.getIsNew()?"true":"false");
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_NAME);
child.setValue(connection.getName());
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_CLASSNAME);
child.setValue(connection.getClassName());
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_MAXCONNECTIONS);
child.setValue(Integer.toString(connection.getMaxConnections()));
connectionNode.addChild(connectionNode.getChildCount(),child);
if (connection.getPrerequisiteMapping() != null)
{
child = new ConfigurationNode(CONNECTIONNODE_PREREQUISITE);
child.setValue(connection.getPrerequisiteMapping());
connectionNode.addChild(connectionNode.getChildCount(),child);
}
if (connection.getDescription() != null)
{
child = new ConfigurationNode(CONNECTIONNODE_DESCRIPTION);
child.setValue(connection.getDescription());
connectionNode.addChild(connectionNode.getChildCount(),child);
}
ConfigParams cp = connection.getConfigParams();
child = new ConfigurationNode(CONNECTIONNODE_CONFIGURATION);
j = 0;
while (j < cp.getChildCount())
{
ConfigurationNode cn = cp.findChild(j++);
child.addChild(child.getChildCount(),cn);
}
connectionNode.addChild(connectionNode.getChildCount(),child);
}
// Mapping connection API methods
/** Convert input hierarchy into an MappingConnection object.
*/
protected static void processMappingConnection(org.apache.manifoldcf.authorities.mapping.MappingConnection connection, ConfigurationNode connectionNode)
throws ManifoldCFException
{
// Walk through the node's children
int i = 0;
while (i < connectionNode.getChildCount())
{
ConfigurationNode child = connectionNode.findChild(i++);
String childType = child.getType();
if (childType.equals(CONNECTIONNODE_ISNEW))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection isnew node requires a value");
connection.setIsNew(child.getValue().equals("true"));
}
else if (childType.equals(CONNECTIONNODE_NAME))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection name node requires a value");
connection.setName(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_CLASSNAME))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection classname node requires a value");
connection.setClassName(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_MAXCONNECTIONS))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection maxconnections node requires a value");
try
{
connection.setMaxConnections(Integer.parseInt(child.getValue()));
}
catch (NumberFormatException e)
{
throw new ManifoldCFException("Error parsing max connections: "+e.getMessage(),e);
}
}
else if (childType.equals(CONNECTIONNODE_PREREQUISITE))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection prerequisite node requires a value");
connection.setPrerequisiteMapping(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_DESCRIPTION))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection description node requires a value");
connection.setDescription(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_CONFIGURATION))
{
// Get the connection's configuration, clear out the children, and copy new ones from the child.
ConfigParams cp = connection.getConfigParams();
cp.clearChildren();
int j = 0;
while (j < child.getChildCount())
{
ConfigurationNode cn = child.findChild(j++);
cp.addChild(cp.getChildCount(),new ConfigNode(cn));
}
}
else
throw new ManifoldCFException("Unrecognized mapping connection field: '"+childType+"'");
}
if (connection.getClassName() == null)
throw new ManifoldCFException("Missing connection field: '"+CONNECTIONNODE_CLASSNAME+"'");
}
/** Format a mapping connection.
*/
protected static void formatMappingConnection(ConfigurationNode connectionNode, IMappingConnection connection)
{
ConfigurationNode child;
int j;
child = new ConfigurationNode(CONNECTIONNODE_ISNEW);
child.setValue(connection.getIsNew()?"true":"false");
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_NAME);
child.setValue(connection.getName());
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_CLASSNAME);
child.setValue(connection.getClassName());
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_MAXCONNECTIONS);
child.setValue(Integer.toString(connection.getMaxConnections()));
connectionNode.addChild(connectionNode.getChildCount(),child);
if (connection.getPrerequisiteMapping() != null)
{
child = new ConfigurationNode(CONNECTIONNODE_PREREQUISITE);
child.setValue(connection.getPrerequisiteMapping());
connectionNode.addChild(connectionNode.getChildCount(),child);
}
if (connection.getDescription() != null)
{
child = new ConfigurationNode(CONNECTIONNODE_DESCRIPTION);
child.setValue(connection.getDescription());
connectionNode.addChild(connectionNode.getChildCount(),child);
}
ConfigParams cp = connection.getConfigParams();
child = new ConfigurationNode(CONNECTIONNODE_CONFIGURATION);
j = 0;
while (j < cp.getChildCount())
{
ConfigurationNode cn = cp.findChild(j++);
child.addChild(child.getChildCount(),cn);
}
connectionNode.addChild(connectionNode.getChildCount(),child);
}
// Repository connection API support methods
/** Convert input hierarchy into a RepositoryConnection object.
*/
protected static void processRepositoryConnection(org.apache.manifoldcf.crawler.repository.RepositoryConnection connection, ConfigurationNode connectionNode)
throws ManifoldCFException
{
// Walk through the node's children
int i = 0;
while (i < connectionNode.getChildCount())
{
ConfigurationNode child = connectionNode.findChild(i++);
String childType = child.getType();
if (childType.equals(CONNECTIONNODE_ISNEW))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection isnew node requires a value");
connection.setIsNew(child.getValue().equals("true"));
}
else if (childType.equals(CONNECTIONNODE_NAME))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection name node requires a value");
connection.setName(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_CLASSNAME))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection classname node requires a value");
connection.setClassName(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_MAXCONNECTIONS))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection maxconnections node requires a value");
try
{
connection.setMaxConnections(Integer.parseInt(child.getValue()));
}
catch (NumberFormatException e)
{
throw new ManifoldCFException("Error parsing max connections: "+e.getMessage(),e);
}
}
else if (childType.equals(CONNECTIONNODE_DESCRIPTION))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection description node requires a value");
connection.setDescription(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_CONFIGURATION))
{
// Get the connection's configuration, clear out the children, and copy new ones from the child.
ConfigParams cp = connection.getConfigParams();
cp.clearChildren();
int j = 0;
while (j < child.getChildCount())
{
ConfigurationNode cn = child.findChild(j++);
cp.addChild(cp.getChildCount(),new ConfigNode(cn));
}
}
else if (childType.equals(CONNECTIONNODE_ACLAUTHORITY))
{
if (child.getValue() == null)
throw new ManifoldCFException("Connection aclauthority node requires a value");
connection.setACLAuthority(child.getValue());
}
else if (childType.equals(CONNECTIONNODE_THROTTLE))
{
String match = null;
String description = null;
Float rate = null;
int q = 0;
while (q < child.getChildCount())
{
ConfigurationNode throttleField = child.findChild(q++);
String fieldType = throttleField.getType();
if (fieldType.equals(CONNECTIONNODE_MATCH))
{
match = throttleField.getValue();
}
else if (fieldType.equals(CONNECTIONNODE_MATCHDESCRIPTION))
{
description = throttleField.getValue();
}
else if (fieldType.equals(CONNECTIONNODE_RATE))
{
rate = new Float(throttleField.getValue());
}
else
throw new ManifoldCFException("Unrecognized throttle field: '"+fieldType+"'");
}
if (match == null)
throw new ManifoldCFException("Missing throttle field: '"+CONNECTIONNODE_MATCH+"'");
if (rate == null)
throw new ManifoldCFException("Missing throttle field: '"+CONNECTIONNODE_RATE+"'");
connection.addThrottleValue(match,description,rate.floatValue());
}
else
throw new ManifoldCFException("Unrecognized repository connection field: '"+childType+"'");
}
if (connection.getClassName() == null)
throw new ManifoldCFException("Missing connection field: '"+CONNECTIONNODE_CLASSNAME+"'");
}
/** Format a repository connection.
*/
protected static void formatRepositoryConnection(ConfigurationNode connectionNode, IRepositoryConnection connection)
{
ConfigurationNode child;
int j;
child = new ConfigurationNode(CONNECTIONNODE_ISNEW);
child.setValue(connection.getIsNew()?"true":"false");
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_NAME);
child.setValue(connection.getName());
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_CLASSNAME);
child.setValue(connection.getClassName());
connectionNode.addChild(connectionNode.getChildCount(),child);
child = new ConfigurationNode(CONNECTIONNODE_MAXCONNECTIONS);
child.setValue(Integer.toString(connection.getMaxConnections()));
connectionNode.addChild(connectionNode.getChildCount(),child);
if (connection.getDescription() != null)
{
child = new ConfigurationNode(CONNECTIONNODE_DESCRIPTION);
child.setValue(connection.getDescription());
connectionNode.addChild(connectionNode.getChildCount(),child);
}
ConfigParams cp = connection.getConfigParams();
child = new ConfigurationNode(CONNECTIONNODE_CONFIGURATION);
j = 0;
while (j < cp.getChildCount())
{
ConfigurationNode cn = cp.findChild(j++);
child.addChild(child.getChildCount(),cn);
}
connectionNode.addChild(connectionNode.getChildCount(),child);
if (connection.getACLAuthority() != null)
{
child = new ConfigurationNode(CONNECTIONNODE_ACLAUTHORITY);
child.setValue(connection.getACLAuthority());
connectionNode.addChild(connectionNode.getChildCount(),child);
}
String[] throttles = connection.getThrottles();
j = 0;
while (j < throttles.length)
{
String match = throttles[j++];
String description = connection.getThrottleDescription(match);
float rate = connection.getThrottleValue(match);
child = new ConfigurationNode(CONNECTIONNODE_THROTTLE);
ConfigurationNode throttleChildNode;
throttleChildNode = new ConfigurationNode(CONNECTIONNODE_MATCH);
throttleChildNode.setValue(match);
child.addChild(child.getChildCount(),throttleChildNode);
if (description != null)
{
throttleChildNode = new ConfigurationNode(CONNECTIONNODE_MATCHDESCRIPTION);
throttleChildNode.setValue(description);
child.addChild(child.getChildCount(),throttleChildNode);
}
throttleChildNode = new ConfigurationNode(CONNECTIONNODE_RATE);
throttleChildNode.setValue(new Float(rate).toString());
child.addChild(child.getChildCount(),throttleChildNode);
connectionNode.addChild(connectionNode.getChildCount(),child);
}
}
// End of connection API code
}