package com.constellio.app.modules.es.connectors.smb; import com.constellio.app.modules.es.connectors.http.ConnectorHttpContext; import com.constellio.app.modules.es.connectors.smb.ConnectorSmbRuntimeException.ConnectorSmbRuntimeException_CannotDelete; import com.constellio.app.modules.es.connectors.smb.cache.SmbConnectorContext; import com.constellio.app.modules.es.connectors.smb.cache.SmbConnectorContextServices; import com.constellio.app.modules.es.connectors.smb.config.SmbRetrievalConfiguration; import com.constellio.app.modules.es.connectors.smb.config.SmbSchemaDisplayConfiguration; import com.constellio.app.modules.es.connectors.smb.jobmanagement.SmbConnectorJob; import com.constellio.app.modules.es.connectors.smb.jobmanagement.SmbDocumentOrFolderUpdater; import com.constellio.app.modules.es.connectors.smb.jobmanagement.SmbJobFactory; import com.constellio.app.modules.es.connectors.smb.jobmanagement.SmbJobFactoryImpl; import com.constellio.app.modules.es.connectors.smb.jobmanagement.SmbJobFactoryImpl.SmbJobCategory; import com.constellio.app.modules.es.connectors.smb.jobs.SmbNullJob; import com.constellio.app.modules.es.connectors.smb.queue.SmbJobQueue; import com.constellio.app.modules.es.connectors.smb.queue.SmbJobQueueSortedImpl; import com.constellio.app.modules.es.connectors.smb.security.Credentials; import com.constellio.app.modules.es.connectors.smb.service.*; import com.constellio.app.modules.es.connectors.smb.utils.ConnectorSmbUtils; import com.constellio.app.modules.es.connectors.smb.utils.SmbUrlComparator; import com.constellio.app.modules.es.connectors.spi.Connector; import com.constellio.app.modules.es.connectors.spi.ConnectorJob; import com.constellio.app.modules.es.model.connectors.ConnectorDocument; import com.constellio.app.modules.es.model.connectors.smb.ConnectorSmbDocument; import com.constellio.app.modules.es.model.connectors.smb.ConnectorSmbFolder; import com.constellio.app.modules.es.model.connectors.smb.ConnectorSmbInstance; import com.constellio.app.modules.es.services.ESSchemasRecordsServices; import com.constellio.app.modules.es.ui.pages.ConnectorReportView; import com.constellio.data.dao.managers.config.ConfigManagerRuntimeException; import com.constellio.data.utils.dev.Toggle; import com.constellio.model.entities.records.Record; import com.constellio.model.entities.records.wrappers.User; import com.constellio.model.services.records.RecordServicesException; import jcifs.smb.NtlmPasswordAuthentication; import jcifs.smb.SmbException; import jcifs.smb.SmbFile; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.util.*; import static java.util.Arrays.asList; public class ConnectorSmb extends Connector { static { System.setProperty("jcifs.smb.client.soTimeout","150000"); System.setProperty("jcifs.smb.client.responseTimeout","120000"); System.setProperty("jcifs.resolveOrder","LMHOSTS,DNS,WINS"); System.setProperty("jcifs.smb.client.listSize","1200"); System.setProperty("jcifs.smb.client.listCount","15"); System.setProperty("jcifs.smb.client.dfs.strictView","true"); } static final String START_OF_TRAVERSAL = "Start of traversal"; static final String RESUME_OF_TRAVERSAL = "Resume of traversal"; static final String END_OF_TRAVERSAL = "End of traversal"; private static final int MAX_JOBS_PER_GET_JOBS_CALL = 500; private ConnectorSmbInstance connectorInstance; private ConnectorSmbUtils smbUtils; private SmbSchemaDisplayConfiguration schemaDisplayConfig; private SmbJobQueue jobsQueue; private SmbShareService smbShareService; private SmbJobFactory smbJobFactory; private SmbRecordService smbRecordService; private SmbDocumentOrFolderUpdater updater; private SmbUrlComparator urlComparator; private String connectorId; private SmbConnectorContext context; private SmbConnectorContextServices contextServices; public ConnectorSmb() { urlComparator = new SmbUrlComparator(); } public ConnectorSmb(SmbShareService smbShareService) { this.smbShareService = smbShareService; urlComparator = new SmbUrlComparator(); } @Override protected void initialize(Record instanceRecord) { this.connectorId = instanceRecord.getId(); this.connectorInstance = getEs().wrapConnectorSmbInstance(instanceRecord); this.smbUtils = new ConnectorSmbUtils(); schemaDisplayConfig = new SmbSchemaDisplayConfiguration(getEs(), connectorInstance); schemaDisplayConfig.setupMetadatasDisplay(); jobsQueue = new SmbJobQueueSortedImpl(); Credentials credentials = new Credentials(connectorInstance.getDomain(), connectorInstance.getUsername(), connectorInstance.getPassword()); SmbRetrievalConfiguration smbRetrievalConfiguration = new SmbRetrievalConfiguration(connectorInstance.getSeeds(), connectorInstance.getInclusions(), connectorInstance.getExclusions(), connectorInstance.isSkipShareAccessControl()); if (smbShareService == null) { smbShareService = new SmbShareServiceSimpleImpl(credentials, smbRetrievalConfiguration, smbUtils, logger, es); } smbRecordService = new SmbRecordService(es, connectorInstance); updater = new SmbDocumentOrFolderUpdater(connectorInstance, smbRecordService); contextServices = new SmbConnectorContextServices(es); smbJobFactory = new SmbJobFactoryImpl(this, connectorInstance, eventObserver, smbShareService, smbUtils, smbRecordService, updater); } @Override public void start() { getLogger().info(START_OF_TRAVERSAL, "Current TraversalCode : " + connectorInstance.getTraversalCode(), new LinkedHashMap<String, String>()); try { context = contextServices.createContext(connectorId); } catch (ConfigManagerRuntimeException.ConfigurationAlreadyExists e) { contextServices.deleteContext(connectorId); context = contextServices.createContext(connectorId); } jobsQueue.clear(); String resumeUrl = connectorInstance.getResumeUrl(); queueSeeds(); } private void queueSeeds() { List<String> sortedSeeds = new ArrayList(connectorInstance.getSeeds()); Collections.sort(sortedSeeds, urlComparator); for (String seed : sortedSeeds) { SmbConnectorJob smbDispatchJob = smbJobFactory.get(SmbJobCategory.SEED, seed, ""); if (!(smbDispatchJob instanceof SmbNullJob)) { queueJob(smbDispatchJob); } } } @Override public void resume() { getLogger().info(RESUME_OF_TRAVERSAL, "Current TraversalCode : " + connectorInstance.getTraversalCode(), new LinkedHashMap<String, String>()); context = contextServices.loadContext(connectorId); jobsQueue.clear(); String resumeUrl = connectorInstance.getResumeUrl(); queueSeeds(); } @Override public void stop() { try { es.getRecordServices() .update(connectorInstance.setResumeUrl("")); } catch (Exception e) { logger.errorUnexpected(e); } } @Override public List<String> fetchTokens(String username) { // Ne pas modifier cette méthode! return new ArrayList<>(); } @Override public void afterJobs(List<ConnectorJob> jobs) { contextServices.save(context); } @Override public List<String> getReportMetadatas(String reportMode) { if (ConnectorReportView.INDEXING.equals(reportMode)) { return Arrays.asList(ConnectorSmbDocument.URL, ConnectorSmbDocument.FETCHED_DATETIME); } else if (ConnectorReportView.ERRORS.equals(reportMode)) { return Arrays.asList(ConnectorSmbDocument.URL, ConnectorSmbDocument.ERROR_CODE, ConnectorSmbDocument.ERROR_MESSAGE, ConnectorSmbDocument.FETCHED_DATETIME); } return new ArrayList<>(); } @Override public String getMainConnectorDocumentType() { return ConnectorSmbDocument.SCHEMA_TYPE; } @Override public void onAllDocumentsDeleted() { // TODO Pat delete config folder for this connector. } @Override public List<ConnectorJob> getJobs() { List<ConnectorJob> jobs = new ArrayList<>(); while (!jobsQueue.isEmpty() && jobs.size() < MAX_JOBS_PER_GET_JOBS_CALL) { SmbConnectorJob queuedJob = jobsQueue.poll(); jobs.add(queuedJob); } if (jobsQueue.isEmpty() && jobs.isEmpty()) { List<String> urlsOfDocumentsToDelete = this.context.staleUrls(this.connectorInstance.getTraversalCode()); // Delete jobs are currently not limited to MAX_JOBS_PER_GET_JOBS_CALL for (String url : urlsOfDocumentsToDelete) { ConnectorJob deleteJob = smbJobFactory.get(SmbJobCategory.DELETE, url, ""); jobs.add(deleteJob); } changeTraversalCodeToMarkEndOfTraversal(); queueSeeds(); } return jobs; } public void queueJob(SmbConnectorJob job) { logger.debug("Queueing job : ", job.toString(), new LinkedHashMap<String, String>()); jobsQueue.add(job); } private void changeTraversalCodeToMarkEndOfTraversal() { String oldTraversalCode = connectorInstance.getTraversalCode(); String newTraversalCode = UUID.randomUUID() .toString(); connectorInstance.setTraversalCode(newTraversalCode); connectorInstance.setResumeUrl(""); try { es.getRecordServices().update(connectorInstance); } catch (RecordServicesException e) { logger.errorUnexpected(e); } getLogger().info(END_OF_TRAVERSAL, "Connector instance " + connectorInstance.getId() + " Old TraversalCode : \"" + oldTraversalCode + "\" New TraversalCode : \"" + newTraversalCode + "\"", new LinkedHashMap<String, String>()); } @Override public List<String> getConnectorDocumentTypes() { return asList(ConnectorSmbDocument.SCHEMA_TYPE, ConnectorSmbFolder.SCHEMA_TYPE); } public void setEs(ESSchemasRecordsServices es) { this.es = es; } private ConnectorSmbUtils getSmbUtils() { return smbUtils; } public InputStream getInputStream(ConnectorSmbDocument document, String resourceName) { if (Toggle.SIMULATE_CONNECTOR_DOWNLOAD_CONTENT.isEnabled()) { String dummyContent = "This is not the content you are looking for"; return new ByteArrayInputStream(dummyContent.getBytes()); } SmbFile smbFile = getSmbFile(document); try { InputStream is = smbFile.getInputStream(); return es.getIOServices().newBufferedInputStream(is, resourceName); } catch (IOException e) { throw new RuntimeException(e); } } public void deleteFile(ConnectorDocument document) { SmbFile smbFile = getSmbFile(document); try { smbFile.delete(); es.getRecordServices().logicallyDelete(document.getWrappedRecord(), User.GOD); } catch (SmbException e) { throw new ConnectorSmbRuntimeException_CannotDelete(document, e); } } public boolean exists(ConnectorDocument document) { SmbFile smbFile = getSmbFile(document); try { return smbFile.exists(); } catch (SmbException e) { throw new RuntimeException(e); } } private SmbFile getSmbFile(ConnectorDocument document) { SmbFileFactory smbFactory = new SmbFileFactoryImpl(); String connectorId = document.getConnector(); if (es == null) { throw new IllegalStateException("Must call setEs(es) before getInputStream()"); } ConnectorSmbInstance connectorInstance = es .getConnectorSmbInstance(connectorId); NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication( connectorInstance.getDomain(), connectorInstance.getUsername(), connectorInstance.getPassword()); try { return smbFactory.getSmbFile(document.getURL(), auth); } catch (MalformedURLException e) { throw new RuntimeException(e); } } public SmbConnectorContext getContext() { return this.context; } }