// Copyright 2006 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.manager; import com.google.common.base.Charsets; import com.google.common.base.Strings; import com.google.enterprise.connector.instantiator.Configuration; import com.google.enterprise.connector.instantiator.ExtendedConfigureResponse; import com.google.enterprise.connector.instantiator.InstantiatorException; import com.google.enterprise.connector.persist.ConnectorExistsException; import com.google.enterprise.connector.persist.ConnectorNotFoundException; import com.google.enterprise.connector.persist.ConnectorTypeNotFoundException; import com.google.enterprise.connector.persist.PersistentStoreException; import com.google.enterprise.connector.spi.AuthenticationIdentity; import com.google.enterprise.connector.spi.AuthenticationResponse; import com.google.enterprise.connector.spi.AuthorizationResponse; import com.google.enterprise.connector.spi.AuthorizationResponse.Status; import com.google.enterprise.connector.spi.ConfigureResponse; import com.google.enterprise.connector.spi.ConnectorType; import com.google.enterprise.connector.spi.Document; import com.google.enterprise.connector.spi.SpiConstants; import com.google.enterprise.connector.test.ConnectorTestUtils; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeSet; import java.util.logging.Logger; /** * A mock implementation for the Manager interface. This implementation * basically hardcodes a bunch of responses and can be used before the actual * implementation is complete. * */ public class MockManager implements Manager { private static final MockManager INSTANCE = new MockManager(); private static final Logger LOGGER = Logger.getLogger(MockManager.class.getName()); private static final String CONNECTOR1 = "connector1"; private static final String CONNECTOR2 = "connector2"; private static final String CONNECTOR3 = "connector3"; private static final String CONNECTOR4 = "connector4"; private static final String CONNECTOR5 = "connector5"; public static final String CONNECTOR6 = "connector6"; public static final String CONNECTOR6_SPECIAL_CHAR_DOCID = "AaZz09-_.~`=/?+';\\/\"!@#$%^&*()[]{}ëこんにちは世界\u0001"; public static final String CONNECTOR6_SUCCESS = "success"; private boolean shouldVerifyIdentity; private String domain; private String username; private String password; private Collection<?> groups; /** Stand-in for the manager.locked property. */ private boolean isLocked = false; // Protected constructor used by JUnit test subclasses. protected MockManager() { shouldVerifyIdentity = false; } public static MockManager getInstance() { return INSTANCE; } @Override public AuthenticationResponse authenticate(String connectorName, AuthenticationIdentity identity) { if (shouldVerifyIdentity) { // Domains connector1 and connector2 only work for their respective // connectors. // This is used to test some connectors failing, but others passing. if ((CONNECTOR1.equals(identity.getDomain()) && !CONNECTOR1.equals(connectorName)) || (CONNECTOR2.equals(identity.getDomain()) && !CONNECTOR2.equals(connectorName))) { return new AuthenticationResponse(false, null, null); } StringBuilder sb = new StringBuilder(); if (!verifyIdentity(identity, sb)) { return new AuthenticationResponse(false, null, null); } } return new AuthenticationResponse(true, null, groups); } // Note this is trying to duplicate the AuthorizationParser.matchesIdentity() // behavior with the difference that this does not fail fast. private boolean verifyIdentity(AuthenticationIdentity identity, StringBuilder sb) { boolean result = true; if (!verifyComponent("domain", domain, identity.getDomain(), sb)) { result = false; } if (!verifyComponent("username", username, identity.getUsername(), sb)) { result = false; } // NULL password means do not authenticate, but return any groups. if (identity.getPassword() != null) { if (!verifyComponent("password", password, identity.getPassword(), sb)) { result = false; } } return result; } private boolean verifyComponent(String componentName, String expected, String actual, StringBuilder sb) { if (expected == null) { if (actual != null) { sb.append("Expected null " + componentName + " got " + actual + "\n"); return false; } return true; } if (!expected.equals(actual)) { sb.append("Expected " + componentName + "\"" + expected + "\" got \"" + actual +"\"\n"); return false; } return true; } @Override public Collection<AuthorizationResponse> authorizeDocids(String connectorName, List<String> docidList, AuthenticationIdentity identity) { // Connector4 always returns a null response. if (CONNECTOR4.equals(connectorName)) { return null; } // Sort the docids, so we process them in a predictable order for testing. docidList = new ArrayList<String>(docidList); Collections.sort(docidList); Set<AuthorizationResponse> results = new TreeSet<AuthorizationResponse>(); StringBuilder sb = new StringBuilder(); boolean permit = (shouldVerifyIdentity)? verifyIdentity(identity, sb) : true; if (sb.length() > 0) { LOGGER.info(sb.toString()); } // Connector1 returns same response for every doc. if (CONNECTOR1.equals(connectorName)) { for (String docid : docidList) { results.add(new AuthorizationResponse(permit, docid)); } } // Connector2 returns indeterminate every other doc. if (CONNECTOR2.equals(connectorName)) { boolean odd = false; Status status = (permit) ? Status.PERMIT : Status.DENY; for (String docid : docidList) { results.add(new AuthorizationResponse( ((odd) ? Status.INDETERMINATE : status), docid)); odd = !odd; } } // Connector3 strictly returns permits, but only every other doc. if (CONNECTOR3.equals(connectorName)) { if (permit) { for (String docid : docidList) { if (permit) { results.add(new AuthorizationResponse(permit, docid)); } permit = !permit; } } } return results; } @Override public InputStream getDocumentContent(String connectorName, String docid) throws ConnectorNotFoundException { if (CONNECTOR1.equals(connectorName)) { return new ByteArrayInputStream(docid.getBytes(Charsets.UTF_8)); } if (CONNECTOR2.equals(connectorName)) { return null; // no content } if (CONNECTOR5.equals(connectorName)) { return new ByteArrayInputStream(docid.getBytes(Charsets.UTF_8)); } if (CONNECTOR6.equals(connectorName)) { if (CONNECTOR6_SPECIAL_CHAR_DOCID.equals(docid)) { return new ByteArrayInputStream( CONNECTOR6_SUCCESS.getBytes(Charsets.UTF_8)); } else { return null; } } throw new ConnectorNotFoundException("Connector not found: " + connectorName); } @Override public Document getDocumentMetaData(String connectorName, String docid) throws ConnectorNotFoundException { if (CONNECTOR1.equals(connectorName) || CONNECTOR6.equals(connectorName)) { Map<String, Object> props = ConnectorTestUtils.createSimpleDocumentBasicProperties(docid); props.remove(SpiConstants.PROPNAME_CONTENT); return ConnectorTestUtils.createSimpleDocument(props); } if (CONNECTOR2.equals(connectorName)) { Map<String, Object> props = ConnectorTestUtils.createSimpleDocumentBasicProperties(docid); props.remove(SpiConstants.PROPNAME_CONTENT); props.remove(SpiConstants.PROPNAME_LASTMODIFIED); props.remove(SpiConstants.PROPNAME_MIMETYPE); return ConnectorTestUtils.createSimpleDocument(props); } if (CONNECTOR5.equals(connectorName)) { Map<String, Object> props = ConnectorTestUtils.createSimpleDocumentBasicProperties(docid); props.remove(SpiConstants.PROPNAME_CONTENT); props.put(SpiConstants.PROPNAME_ISPUBLIC, false); return ConnectorTestUtils.createSimpleDocument(props); } throw new ConnectorNotFoundException("Connector not found: " + connectorName); } @Override public Set<String> getConnectorTypeNames() { return new TreeSet<String>(Arrays.asList( new String[] {"Documentum", "Filenet", "Sharepoint"})); } @Override public ConnectorType getConnectorType(String typeName) throws ConnectorTypeNotFoundException { throw new ConnectorTypeNotFoundException("Unsupported Operation"); } public String getConnectorInstancePrototype(String typeName) { return "<?xml?><beans><bean id=\"" + typeName + "Instance\"/></beans>"; } @Override public ConfigureResponse getConfigForm(String connectorTypeName, String language) throws InstantiatorException { String message = "Sample form for " + connectorTypeName + "lang " + language; String formSnippet = " <tr><td>Repository</td>" + " <td><input type=\"text\" name=\"repository\" value=\"\"></td>" + " </tr>" + " <tr><td>Username</td>" + " <td><input type=\"text\" name=\"username\" value=\"\">" + " </td></tr>" + " <tr><td>Password</td>" + " <td><input type=\"password\" name=\"passwd\" value=\"\">" + " </td></tr>" + " <tr><td>Seed URIs</td>" + " <td><textarea name=\"seedUris\"></textarea></td></tr>"; return new ExtendedConfigureResponse(new ConfigureResponse(message, formSnippet), getConnectorInstancePrototype(connectorTypeName)); } @Override public ConfigureResponse getConfigFormForConnector(String connectorName, String language) throws InstantiatorException { String message = "Sample form for " + connectorName + "lang " + language; String formSnippet = "<tr>\n" + "<td>Username</td>\n" + "<td>\n" + "<input type=\"text\" name=\"Username\" />\n" + "</td>\n" + "</tr>\n" + "<tr>\n" + "<td>Password</td>\n" + "<td>\n" + "<input type=\"password\" name=\"Password\" />\n" + "</td>\n" + "</tr>\n" + "<tr>\n" + "<td>Color</td>\n" + "<td>\n" + "<input type=\"text\" name=\"Color\" />\n" + "</td>\n" + "</tr>\n" + "<tr>\n" + "<td>Repository File</td>\n" + "<td>\n" + "<input type=\"text\" name=\"Repository File\" />\n" + "</td>\n" + "</tr>\n"; return new ConfigureResponse(message, formSnippet); } @Override public ConnectorStatus getConnectorStatus(String connectorName) throws ConnectorNotFoundException { String name = connectorName; String type = "Documentum"; int status = 0; String schedule = connectorName + ":100:0:0-0"; return new ConnectorStatus(name, type, status, schedule, null, null); } @Override public List<ConnectorStatus> getConnectorStatuses() { List<ConnectorStatus> statuses = new ArrayList<ConnectorStatus>(); try { statuses.add(getConnectorStatus(CONNECTOR1)); statuses.add(getConnectorStatus(CONNECTOR2)); } catch (ConnectorNotFoundException ignored) { // Ignored. } return statuses; } @Override public ConfigureResponse setConnectorConfiguration(String connectorName, Configuration configuration, String language, boolean update) throws ConnectorNotFoundException, ConnectorExistsException, PersistentStoreException, InstantiatorException { LOGGER.info("setConnectorConfig() connectorName: " + connectorName); LOGGER.info("setConnectorConfig() update: " + update); LOGGER.info("configData: "); for (Map.Entry<String, String> entry : configuration.getMap().entrySet()) { LOGGER.info(entry.getKey() + "/" + entry.getValue()); } if (configuration.getXml() == null) { LOGGER.info("configXml: null"); } else { LOGGER.info("configXml:"); LOGGER.info(configuration.getXml()); } // null is a success response return null; } @Override public Configuration getConnectorConfiguration(String connectorName) throws ConnectorNotFoundException { return new Configuration("Mock", new HashMap<String, String>(), null); } final Properties managerConfig = new Properties(); @Override public Properties getConnectorManagerConfig() { return managerConfig; } @Override public void setConnectorManagerConfig(String feederGateProtocol, String feederGateHost, int feederGatePort, int feederGateSecurePort, String connectorManagerUrl) { if (!Strings.isNullOrEmpty(feederGateProtocol)) { managerConfig.put(Context.GSA_FEED_PROTOCOL_PROPERTY_KEY, feederGateProtocol); } if (!Strings.isNullOrEmpty(feederGateHost)) { managerConfig.put(Context.GSA_FEED_HOST_PROPERTY_KEY, feederGateHost); } managerConfig.put(Context.GSA_FEED_PORT_PROPERTY_KEY, String.valueOf(feederGatePort)); if (feederGateSecurePort >= 0) { managerConfig.put(Context.GSA_FEED_SECURE_PORT_PROPERTY_KEY, String.valueOf(feederGateSecurePort)); } if (!Strings.isNullOrEmpty(connectorManagerUrl)) { managerConfig.put(Context.FEED_CONTENTURL_PREFIX_PROPERTY_KEY, connectorManagerUrl + Context.FEED_CONTENTURL_SERVLET); } isLocked = true; } @Override public void setSchedule(String connectorName, String schedule) throws ConnectorNotFoundException, PersistentStoreException { // do nothing } @Override public void removeConnector(String connectorName) throws ConnectorNotFoundException, PersistentStoreException { if (CONNECTOR2.equals(connectorName)) { throw new ConnectorNotFoundException(); } LOGGER.info("Removing connector: " + connectorName); } @Override public void restartConnectorTraversal(String connectorName) throws ConnectorNotFoundException, InstantiatorException { // do nothing; } @Override public boolean isLocked() { return isLocked; } /** The tests need to reset isLocked. */ public void setLocked(boolean isLocked) { this.isLocked = isLocked; } public void setShouldVerifyIdentity(boolean b) { shouldVerifyIdentity = b; } public void setExpectedIdentity(String domain, String username, String password, Collection<?> groups) { this.domain = domain; this.username = username; this.password = password; this.groups = groups; } }