Java tutorial
/* * Copyright 2011-2012 Alfresco Software Limited. * * 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. * * This file is part of an unsupported extension to Alfresco. */ package org.alfresco.dropbox.service.polling; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import org.alfresco.dropbox.DropboxConstants; import org.alfresco.dropbox.exceptions.NotModifiedException; import org.alfresco.dropbox.service.DropboxService; import org.alfresco.model.ContentModel; import org.alfresco.repo.search.impl.lucene.LuceneQueryParserException; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.social.dropbox.api.Metadata; /** * * * @author Jared Ottley */ public class DropboxPollerImpl implements DropboxPoller { private static final Log log = LogFactory.getLog(DropboxPollerImpl.class); private SearchService searchService; private NodeService nodeService; private FileFolderService fileFolderService; private TransactionService transactionService; private DropboxService dropboxService; private static final String CMIS_DROPBOX_SITES_QUERY = "SELECT * FROM st:site AS S JOIN db:syncable AS O ON S.cmis:objectId = O.cmis:objectId"; private static final String CMIS_DROPBOX_DOCUMENTS_QUERY = "SELECT D.* FROM cmis:document AS D JOIN db:dropbox AS O ON D.cmis:objectId = O.cmis:objectId"; private static final String CMIS_DROPBOX_FOLDERS_QUERY = "SELECT F.* FROM cmis:folder AS F JOIN db:dropbox AS O ON F.cmis:objectId = O.cmis:objectId"; private static final NodeRef MISSING_NODE = new NodeRef("missing://missing/missing"); public void setSearchService(SearchService searchService) { this.searchService = searchService; } public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; } public void setFileFolderService(FileFolderService fileFolderService) { this.fileFolderService = fileFolderService; } public void setTransactionService(TransactionService transactionService) { this.transactionService = transactionService; } public void setDropboxService(DropboxService dropboxService) { this.dropboxService = dropboxService; } public void execute() { log.debug("Dropbox poller initiated."); // TODO where should the authentication and transactions go? AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() { public Object doWork() throws Exception { RetryingTransactionCallback<Object> txnWork = new RetryingTransactionCallback<Object>() { public Object execute() throws Exception { List<NodeRef> sites = getSites(); List<NodeRef> folders = null; List<NodeRef> documents = null; if (sites != null) { for (NodeRef site : sites) { if (!isSyncing(site)) { log.debug("Processing Content in " + nodeService.getProperty(site, ContentModel.PROP_NAME)); try { syncOn(site); folders = getFolders(site); documents = getDocuments(site); if (documents != null) { // If the document is the child of a synced folder...we want to work on the folder as a // full collection and not the document as an independent element Iterator<NodeRef> i = documents.iterator(); while (i.hasNext()) { NodeRef document = i.next(); if (folders.contains( nodeService.getPrimaryParent(document).getParentRef())) { i.remove(); } } if (documents.size() > 0) { for (NodeRef document : documents) { updateNode(document); } } } if (folders.size() > 0) { for (NodeRef folder : folders) { log.debug("Looking for updates/new content in " + nodeService.getProperty(folder, ContentModel.PROP_NAME)); try { Metadata metadata = dropboxService.getMetadata(folder); // Get the list of the content returned. List<Metadata> list = metadata.getContents(); for (Metadata child : list) { String name = child.getPath().replaceAll( Matcher.quoteReplacement(metadata.getPath() + "/"), ""); NodeRef childNodeRef = fileFolderService .searchSimple(folder, name); if (childNodeRef == null) { addNode(folder, child, name); } else { updateNode(childNodeRef, child); } } metadata = dropboxService.getMetadata(folder); dropboxService.persistMetadata(metadata, folder); } catch (NotModifiedException nme) { // TODO } } } } finally { syncOff(site); log.debug("End processing " + nodeService.getProperty(site, ContentModel.PROP_NAME)); documents = null; folders = null; } } } } return null; } }; transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, false); return null; } }, AuthenticationUtil.getAdminUserName()); } private List<NodeRef> getSites() { List<NodeRef> sites = new ArrayList<NodeRef>(); ResultSet resultSet = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<ResultSet>() { public ResultSet doWork() throws Exception { ResultSet resultSet = null; try { resultSet = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_CMIS_ALFRESCO, CMIS_DROPBOX_SITES_QUERY); } catch (LuceneQueryParserException lqpe) { // This is primarily to handle the case where the dropbox model has not been added to solr yet. Incidentally it // catches other failures too ;) log.info("Unable to perform site query: " + lqpe.getMessage()); } return resultSet; } }, AuthenticationUtil.getAdminUserName()); // TODO Hopefully one day this will go away --Open Bug?? try { if (resultSet.length() > 0) { if (!resultSet.getNodeRef(0).equals(MISSING_NODE)) { sites = resultSet.getNodeRefs(); log.debug("Sites with Dropbox content: " + sites); } } } finally { resultSet.close(); } return sites; } private List<NodeRef> getDocuments(final NodeRef nodeRef) { List<NodeRef> documents = Collections.synchronizedList(new ArrayList<NodeRef>()); ResultSet resultSet = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<ResultSet>() { public ResultSet doWork() throws Exception { ResultSet resultSet = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_CMIS_ALFRESCO, CMIS_DROPBOX_DOCUMENTS_QUERY + " WHERE IN_TREE(D, '" + nodeRef + "')"); return resultSet; } }, AuthenticationUtil.getAdminUserName()); try { // TODO Hopefully one day this will go away --Open Bug?? if (resultSet.length() > 0) { if (!resultSet.getNodeRef(0).equals(MISSING_NODE)) { documents = resultSet.getNodeRefs(); log.debug("Documents synced to Dropbox: " + documents); } } } finally { resultSet.close(); } return documents; } private List<NodeRef> getFolders(final NodeRef nodeRef) { List<NodeRef> folders = Collections.synchronizedList(new ArrayList<NodeRef>()); ResultSet resultSet = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<ResultSet>() { public ResultSet doWork() throws Exception { ResultSet resultSet = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_CMIS_ALFRESCO, CMIS_DROPBOX_FOLDERS_QUERY + " WHERE IN_TREE(F, '" + nodeRef + "')"); return resultSet; } }, AuthenticationUtil.getAdminUserName()); try { // TODO Hopefully one day this will go away --Open Bug?? if (resultSet.length() > 0) { if (!resultSet.getNodeRef(0).equals(MISSING_NODE)) { folders = resultSet.getNodeRefs(); log.debug("Folders synced to Dropbox: " + folders); } } } finally { resultSet.close(); } return folders; } private void updateNode(final NodeRef nodeRef) { Metadata metadata = dropboxService.getMetadata(nodeRef); updateNode(nodeRef, metadata); } private void updateNode(final NodeRef nodeRef, final Metadata metadata) { AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() { public Object doWork() throws Exception { RetryingTransactionCallback<Object> txnWork = new RetryingTransactionCallback<Object>() { public Object execute() throws Exception { if (nodeService.getType(nodeRef).equals(ContentModel.TYPE_FOLDER)) { try { Metadata metadata = dropboxService.getMetadata(nodeRef); // Get the list of the content returned. List<Metadata> list = metadata.getContents(); for (Metadata child : list) { String name = child.getPath() .replaceAll(Matcher.quoteReplacement(metadata.getPath() + "/"), ""); NodeRef childNodeRef = fileFolderService.searchSimple(nodeRef, name); if (childNodeRef == null) { addNode(nodeRef, child, name); } else { updateNode(childNodeRef, child); } } metadata = dropboxService.getMetadata(nodeRef); dropboxService.persistMetadata(metadata, nodeRef); } catch (NotModifiedException nme) { } } else { Serializable rev = nodeService.getProperty(nodeRef, DropboxConstants.Model.PROP_REV); if (!metadata.getRev().equals(rev)) { Metadata metadata = null; try { metadata = dropboxService.getFile(nodeRef); } catch (ContentIOException cio) { cio.printStackTrace(); } if (metadata != null) { dropboxService.persistMetadata(metadata, nodeRef); } else { throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Dropbox metadata maybe out of sync for " + nodeRef); } } } return null; } }; transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, false); return null; } }, AuthenticationUtil.getAdminUserName()); } private void addNode(final NodeRef parentNodeRef, final Metadata metadata, final String name) { AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() { public Object doWork() throws Exception { NodeRef nodeRef = null; if (metadata.isDir()) { RetryingTransactionCallback<NodeRef> txnWork = new RetryingTransactionCallback<NodeRef>() { public NodeRef execute() throws Exception { NodeRef nodeRef = null; nodeRef = fileFolderService.create(parentNodeRef, name, ContentModel.TYPE_FOLDER) .getNodeRef(); Metadata metadata = dropboxService.getMetadata(nodeRef); List<Metadata> list = metadata.getContents(); for (Metadata child : list) { String name = child.getPath() .replaceAll(Matcher.quoteReplacement(metadata.getPath() + "/"), ""); addNode(nodeRef, child, name); } return nodeRef; } }; nodeRef = transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, false); } else { log.debug("Adding " + metadata.getPath() + " to Alfresco"); RetryingTransactionCallback<NodeRef> txnWork = new RetryingTransactionCallback<NodeRef>() { public NodeRef execute() throws Exception { NodeRef nodeRef = null; try { nodeRef = fileFolderService.create(parentNodeRef, name, ContentModel.TYPE_CONTENT) .getNodeRef(); Metadata metadata = dropboxService.getFile(nodeRef); dropboxService.persistMetadata(metadata, parentNodeRef); } catch (ContentIOException cio) { cio.printStackTrace(); } return nodeRef; } }; nodeRef = transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, false); } dropboxService.persistMetadata(metadata, nodeRef); return null; } }, AuthenticationUtil.getAdminUserName()); } private boolean isSyncing(final NodeRef nodeRef) { Boolean syncing = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Boolean>() { public Boolean doWork() throws Exception { RetryingTransactionCallback<Boolean> txnWork = new RetryingTransactionCallback<Boolean>() { public Boolean execute() throws Exception { boolean syncing = false; if (nodeRef != null) { List<ChildAssociationRef> childAssoc = nodeService.getChildAssocs(nodeRef, DropboxConstants.Model.ASSOC_SYNC_DETAILS, DropboxConstants.Model.DROPBOX); if (childAssoc.size() == 1) { syncing = Boolean.valueOf(nodeService.getProperty(childAssoc.get(0).getChildRef(), DropboxConstants.Model.PROP_SYNCING).toString()); } } return syncing; } }; boolean syncing = transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, false); return syncing; } }, AuthenticationUtil.getAdminUserName()); return syncing; } private void syncOn(NodeRef site) { sync(site, true); } private void syncOff(NodeRef site) { sync(site, false); } private void sync(final NodeRef site, final boolean sync) { AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() { public Object doWork() throws Exception { RetryingTransactionCallback<Object> txnWork = new RetryingTransactionCallback<Object>() { public Object execute() throws Exception { if (nodeService.hasAspect(site, DropboxConstants.Model.ASPECT_SYNCABLE)) { List<ChildAssociationRef> childAssoc = nodeService.getChildAssocs(site, DropboxConstants.Model.ASSOC_SYNC_DETAILS, DropboxConstants.Model.DROPBOX); if (childAssoc.size() == 1) { nodeService.setProperty(childAssoc.get(0).getChildRef(), DropboxConstants.Model.PROP_SYNCING, sync); } } return null; } }; transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, false); return null; } }, AuthenticationUtil.getAdminUserName()); } }