// Copyright 2009 Google Inc.
//
// Licensed 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 com.google.enterprise.connector.instantiator;
import com.google.enterprise.connector.jcr.JcrConnector;
import com.google.enterprise.connector.mock.MockRepository;
import com.google.enterprise.connector.mock.MockRepositoryEventList;
import com.google.enterprise.connector.mock.jcr.MockJcrRepository;
import com.google.enterprise.connector.persist.ConnectorExistsException;
import com.google.enterprise.connector.persist.ConnectorNotFoundException;
import com.google.enterprise.connector.persist.MockPersistentStore;
import com.google.enterprise.connector.persist.PersistentStore;
import com.google.enterprise.connector.persist.StoreContext;
import com.google.enterprise.connector.pusher.MockPusher;
import com.google.enterprise.connector.scheduler.Schedule;
import com.google.enterprise.connector.spi.AuthenticationIdentity;
import com.google.enterprise.connector.spi.AuthenticationManager;
import com.google.enterprise.connector.spi.AuthenticationResponse;
import com.google.enterprise.connector.spi.AuthorizationManager;
import com.google.enterprise.connector.spi.AuthorizationResponse;
import com.google.enterprise.connector.spi.ConfigureResponse;
import com.google.enterprise.connector.spi.Connector;
import com.google.enterprise.connector.spi.ConnectorType;
import com.google.enterprise.connector.spi.MockConnectorType;
import com.google.enterprise.connector.spi.Retriever;
import com.google.enterprise.connector.spi.Session;
import com.google.enterprise.connector.spi.SimpleTraversalContext;
import com.google.enterprise.connector.spi.TraversalContext;
import com.google.enterprise.connector.spi.TraversalManager;
import com.google.enterprise.connector.traversal.CancellableQueryTraverser;
import com.google.enterprise.connector.traversal.InterruptibleQueryTraverser;
import com.google.enterprise.connector.traversal.LongRunningQueryTraverser;
import com.google.enterprise.connector.traversal.NeverEndingQueryTraverser;
import com.google.enterprise.connector.traversal.NoopQueryTraverser;
import com.google.enterprise.connector.traversal.QueryTraverser;
import com.google.enterprise.connector.traversal.TraversalStateStore;
import com.google.enterprise.connector.traversal.Traverser;
import com.google.enterprise.connector.util.SystemClock;
import com.google.enterprise.connector.util.filter.DocumentFilterFactory;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jcr.Repository;
/**
* Mock implementation of {@link Instantiator} that comes with support for
* adding predefined connectors {@link #setupTestTraversers()} and support
* for clients to add there own using {@link #setupConnector(String, String)}
* or {@link #setupTraverser(String, Traverser)};
*/
public class MockInstantiator implements Instantiator {
private static final Logger LOGGER =
Logger.getLogger(MockInstantiator.class.getName());
public static final String TRAVERSER_NAME1 = "foo";
public static final String TRAVERSER_NAME2 = "bar";
public static final String TRAVERSER_NAME_NOOP = "noop";
public static final String TRAVERSER_NAME_LONG_RUNNING = "longrunning";
public static final String TRAVERSER_NAME_NEVER_ENDING = "neverending";
public static final String TRAVERSER_NAME_INTERRUPTIBLE = "interruptible";
public static final String TRAVERSER_NAME_CANCELLABLE = "cancellable";
private static final AuthenticationManager nullAuthenticationManager =
new AuthenticationManager() {
public AuthenticationResponse authenticate(
AuthenticationIdentity identity) {
throw new UnsupportedOperationException();
}
};
private static final AuthorizationManager nullAuthorizationManager =
new AuthorizationManager() {
public Collection<AuthorizationResponse> authorizeDocids(
Collection<String> docids, AuthenticationIdentity identity) {
throw new UnsupportedOperationException();
}
};
private final Map<String, ConnectorCoordinator> connectorMap;
private final PersistentStore persistentStore;
private final ThreadPool threadPool;
private final TraversalContext traversalContext;
public MockInstantiator(ThreadPool threadPool) {
this(new MockPersistentStore(), threadPool);
}
public MockInstantiator(PersistentStore persistentStore,
ThreadPool threadPool) {
this.persistentStore = persistentStore;
this.connectorMap = new HashMap<String, ConnectorCoordinator>();
this.threadPool = threadPool;
this.traversalContext = new SimpleTraversalContext();
}
@Override
public synchronized void shutdown(boolean interrupt, long timeoutMillis) {
for (Map.Entry<String, ConnectorCoordinator> e : connectorMap.entrySet()) {
e.getValue().shutdown();
}
connectorMap.clear();
}
private StoreContext getStoreContext(String name) {
return new StoreContext(name, "testType");
}
/**
* Creates and registers a suite of test connectors with this
* {@link Instantiator}.
*/
public void setupTestTraversers() {
setupConnector(TRAVERSER_NAME1, "MockRepositoryEventLog1.txt");
setupConnector(TRAVERSER_NAME2, "MockRepositoryEventLog1.txt");
setupTraverser(TRAVERSER_NAME_NOOP, new NoopQueryTraverser());
setupTraverser(TRAVERSER_NAME_LONG_RUNNING,
new LongRunningQueryTraverser());
setupTraverser(TRAVERSER_NAME_NEVER_ENDING,
new NeverEndingQueryTraverser());
setupTraverser(TRAVERSER_NAME_INTERRUPTIBLE,
new InterruptibleQueryTraverser());
setupTraverser(TRAVERSER_NAME_CANCELLABLE,
new CancellableQueryTraverser());
}
/**
* Creates and registers a {@link Connector} for the provided
* {@link Traverser} with this {@link Instantiator}.
*/
public void setupTraverser(String traverserName, Traverser traverser) {
StoreContext storeContext = getStoreContext(traverserName);
ConnectorInterfaces interfaces = new ConnectorInterfaces(traverserName,
null, nullAuthenticationManager, nullAuthorizationManager);
ConnectorCoordinator cc =
new MockConnectorCoordinator(traverserName, interfaces, traverser,
persistentStore, storeContext, threadPool);
connectorMap.put(traverserName, cc);
}
/**
* Creates a {@link JcrConnector} with a backing {@link MockRepository} and
* registers the created connector with this {@link Instantiator}.
*/
public void setupConnector(String connectorName, String resourceName) {
MockRepositoryEventList mrel = new MockRepositoryEventList(resourceName);
MockRepository mockRepository = new MockRepository(mrel);
Repository repository = new MockJcrRepository(mockRepository);
Connector connector = new JcrConnector(repository);
addConnector(connectorName, connector);
}
/**
* Registers the supplied {@link Connector} with this {@link Instantiator}.
*/
public void addConnector(String connectorName, Connector connector) {
TraversalManager traversalManager;
try {
Session session = connector.login();
traversalManager = session.getTraversalManager();
} catch (Exception e) {
// won't happen
e.printStackTrace();
throw new RuntimeException();
}
StoreContext storeContext = getStoreContext(connectorName);
QueryTraverser queryTraverser =
new QueryTraverser(new MockPusher(), traversalManager,
new MockTraversalStateStore(persistentStore, storeContext),
connectorName, traversalContext,
new SystemClock() /* TODO: use a mock clock */, null);
ConnectorInterfaces interfaces =
new ConnectorInterfaces(connectorName, connector);
ConnectorCoordinator cc =
new MockConnectorCoordinator(connectorName, interfaces, queryTraverser,
persistentStore, storeContext, threadPool);
connectorMap.put(connectorName, cc);
}
@Override
public ConnectorType getConnectorType(String connectorTypeName) {
return new MockConnectorType(connectorTypeName);
}
/**
* Creates a TraversalStateStore for the connector instance.
*
* @return a new TraversalStateStore
*/
public TraversalStateStore getTraversalStateStore(String connectorName) {
return new MockTraversalStateStore(persistentStore,
getStoreContext(connectorName));
}
@Override
public void restartConnectorTraversal(String connectorName)
throws ConnectorNotFoundException {
ConnectorCoordinator cc = connectorMap.get(connectorName);
cc.restartConnectorTraversal();
}
@Override
public String getConnectorInstancePrototype(String connectorTypeName) {
return "";
}
@Override
public Set<String> getConnectorTypeNames() {
return connectorMap.keySet();
}
@Override
public void removeConnector(String connectorName) {
ConnectorCoordinator cc = connectorMap.remove(connectorName);
if (cc != null) {
cc.removeConnector();
}
}
/**
* Returns an {@Link AuthenticationManager}.
*/
@Override
public AuthenticationManager getAuthenticationManager(String connectorName)
throws ConnectorNotFoundException, InstantiatorException {
return getConnectorCoordinator(connectorName).getAuthenticationManager();
}
/**
* Returns an {@Link AuthorizationManager}.
*/
@Override
public AuthorizationManager getAuthorizationManager(String connectorName)
throws ConnectorNotFoundException, InstantiatorException {
return getConnectorCoordinator(connectorName).getAuthorizationManager();
}
/** Returns a {@Link Retreiver}. */
@Override
public Retriever getRetriever(String connectorName)
throws ConnectorNotFoundException, InstantiatorException {
return getConnectorCoordinator(connectorName).getRetriever();
}
@Override
public void startBatch(String connectorName)
throws ConnectorNotFoundException {
getConnectorCoordinator(connectorName).startBatch();
}
@Override
public ConfigureResponse getConfigFormForConnector(String connectorName,
String connectorTypeName, Locale locale) throws ConnectorNotFoundException
{
Configuration config = getConnectorConfiguration(connectorName);
return new MockConnectorType(connectorTypeName)
.getPopulatedConfigForm((config == null) ? null : config.getMap(),
locale);
}
@Override
public Set<String> getConnectorNames() {
return connectorMap.keySet();
}
@Override
public String getConnectorTypeName(String connectorName)
throws ConnectorNotFoundException {
return getConnectorCoordinator(connectorName).getConnectorTypeName();
}
@Override
public ConfigureResponse setConnectorConfiguration(String connectorName,
Configuration configuration, Locale locale, boolean update)
throws ConnectorNotFoundException, ConnectorExistsException,
InstantiatorException {
ConnectorCoordinator cc = getConnectorCoordinator(connectorName);
if (update) {
if (!cc.getConnectorTypeName().equals(configuration.getTypeName())) {
throw new UnsupportedOperationException(
"MockInstantiator does not support changing a connectors type");
}
}
return cc.setConnectorConfiguration(null, configuration, locale, update);
}
@Override
public Configuration getConnectorConfiguration(String connectorName)
throws ConnectorNotFoundException {
return getConnectorCoordinator(connectorName).getConnectorConfiguration();
}
@Override
public void setConnectorSchedule(String connectorName,
Schedule schedule) throws ConnectorNotFoundException {
getConnectorCoordinator(connectorName).setConnectorSchedule(schedule);
}
@Override
public Schedule getConnectorSchedule(String connectorName)
throws ConnectorNotFoundException {
return getConnectorCoordinator(connectorName).getConnectorSchedule();
}
public void setConnectorState(String connectorName, String state)
throws ConnectorNotFoundException {
getConnectorCoordinator(connectorName).setConnectorState(state);
}
public String getConnectorState(String connectorName)
throws ConnectorNotFoundException {
return getConnectorCoordinator(connectorName).getConnectorState();
}
@Override
public DocumentFilterFactory getDocumentFilterFactory(String connectorName)
throws ConnectorNotFoundException {
return null;
}
public void setGDataConfig() {
for (String name : getConnectorNames()) {
try {
getConnectorCoordinator(name).setGDataConfig();
} catch (ConnectorNotFoundException cnfe) {
// Shouldn't happen, but if it does, skip it.
} catch (InstantiatorException ie) {
LOGGER.log(Level.WARNING, "", ie);
}
}
}
private ConnectorCoordinator getConnectorCoordinator(String connectorName)
throws ConnectorNotFoundException {
if (connectorMap.containsKey(connectorName)) {
return connectorMap.get(connectorName);
} else {
throw new ConnectorNotFoundException("Connector not found: "
+ connectorName);
}
}
}