From 480181d6ea83fe29d323a92d628ca8d5d0bd16ca Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Mon, 1 Sep 2008 13:56:46 +0000 Subject: [PATCH] Merged V2.9 to HEAD 10531: Merged V2.2 to V2.9 9928: Optimise & consolidate get web project user role (ETWOTWO-568) 9962: Reverted rev 9902 of RuleServiceImpl 9964: Fixed transaction read-only declaration 9979: ETWOTWO-572: Allow OpenOffice to be called remotely 9987: Second attempt at fixing ETWOTWO-438: versionable aspect and invite user 10096: Fix for ETWOTWO-507 FSR Service Port 10224: Fix for ETWOTWO-507 (inconsistent results with add and delete together) 10225: Adding logging and making FSR work with absolute directories (ETWOTWO-70 and ETWOONE-81) 10254: ALFCOM-242, ALFCOM-230, ETWOTWO-437 10283: Fixed deployment installer builder to use IJ v1.2.7 10359: Add Display Group for deployment servers to JSF client (ETWOTWO-474) 10536: MT - simple setup/system test 10553: Hid domain objects completely within the UsageDeltaDAO git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10613 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../remote-openoffice-context.xml.sample | 14 + config/alfresco/hibernate-context.xml | 11 +- config/alfresco/model/wcmAppModel.xml | 4 + config/alfresco/usage-services-context.xml | 1 - .../java/org/alfresco/model/WCMAppModel.java | 1 + .../avm/locking/AVMLockingServiceImpl.java | 41 +- .../RemoteOpenOfficeContentTransformer.java | 240 ++++++++ .../repo/deploy/DeploymentServiceImpl.java | 34 +- .../repo/{usage => domain}/UsageDelta.java | 2 +- .../hibernate/HibernateUsageDeltaDAO.java | 71 ++- .../repo/domain/hibernate/UsageDelta.hbm.xml | 18 +- .../hibernate/UsageDeltaImpl.java | 4 +- .../HibernateNodeDaoServiceImpl.java | 2 +- .../index/MissingContentReindexComponent.java | 2 +- .../alfresco/repo/rule/RuleServiceImpl.java | 14 +- .../repo/tenant/MultiTDemoSystemTest.java | 566 ++++++++++++++++++ .../alfresco/repo/tenant/TenantService.java | 39 ++ .../alfresco/repo/usage/UsageDeltaDAO.java | 17 +- .../alfresco/repo/usage/UsageServiceImpl.java | 49 +- .../service/cmr/usage/UsageService.java | 2 + 20 files changed, 1023 insertions(+), 109 deletions(-) create mode 100644 config/alfresco/extension/remote-openoffice-context.xml.sample create mode 100644 source/java/org/alfresco/repo/content/transform/RemoteOpenOfficeContentTransformer.java rename source/java/org/alfresco/repo/{usage => domain}/UsageDelta.java (97%) rename source/java/org/alfresco/repo/{usage => domain}/hibernate/HibernateUsageDeltaDAO.java (70%) rename source/java/org/alfresco/repo/{usage => domain}/hibernate/UsageDeltaImpl.java (96%) create mode 100755 source/java/org/alfresco/repo/tenant/MultiTDemoSystemTest.java diff --git a/config/alfresco/extension/remote-openoffice-context.xml.sample b/config/alfresco/extension/remote-openoffice-context.xml.sample new file mode 100644 index 0000000000..0c1c5b8e88 --- /dev/null +++ b/config/alfresco/extension/remote-openoffice-context.xml.sample @@ -0,0 +1,14 @@ + + + + + + + + + + + classpath:alfresco/mimetype/openoffice-document-formats.xml + + + diff --git a/config/alfresco/hibernate-context.xml b/config/alfresco/hibernate-context.xml index 6300efa860..e36923cff6 100644 --- a/config/alfresco/hibernate-context.xml +++ b/config/alfresco/hibernate-context.xml @@ -322,10 +322,13 @@ - - - - + + + + + + + diff --git a/config/alfresco/model/wcmAppModel.xml b/config/alfresco/model/wcmAppModel.xml index d5095cd657..b1666dd28e 100644 --- a/config/alfresco/model/wcmAppModel.xml +++ b/config/alfresco/model/wcmAppModel.xml @@ -302,6 +302,10 @@ Display Name d:text + + Display Name + d:text + Username d:text diff --git a/config/alfresco/usage-services-context.xml b/config/alfresco/usage-services-context.xml index a0a3973ebb..f45bbe32d2 100644 --- a/config/alfresco/usage-services-context.xml +++ b/config/alfresco/usage-services-context.xml @@ -6,7 +6,6 @@ - diff --git a/source/java/org/alfresco/model/WCMAppModel.java b/source/java/org/alfresco/model/WCMAppModel.java index c5ccf19f33..d75d5f3407 100644 --- a/source/java/org/alfresco/model/WCMAppModel.java +++ b/source/java/org/alfresco/model/WCMAppModel.java @@ -83,6 +83,7 @@ public interface WCMAppModel static final QName PROP_DEPLOYSERVERNAME = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployservername"); static final QName PROP_DEPLOYSERVERUSERNAME = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserverusername"); static final QName PROP_DEPLOYSERVERPASSWORD = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserverpassword"); + static final QName PROP_DEPLOYSERVERGROUP = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployservergroup"); static final QName PROP_DEPLOYSERVERURL = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserverurl"); static final QName PROP_DEPLOYSERVERTARGET = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployservertarget"); static final QName PROP_DEPLOYSOURCEPATH = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploysourcepath"); diff --git a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java index a4ae2bcc3c..fa9d17854e 100644 --- a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java @@ -41,7 +41,6 @@ import org.alfresco.service.cmr.avm.AVMExistsException; import org.alfresco.service.cmr.avm.AVMNotFoundException; import org.alfresco.service.cmr.avm.locking.AVMLock; import org.alfresco.service.cmr.avm.locking.AVMLockingService; -import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; @@ -50,7 +49,7 @@ import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.namespace.RegexQNamePattern; +import org.alfresco.service.namespace.NamespaceService; import org.alfresco.util.MD5; import org.alfresco.util.Pair; import org.apache.commons.logging.Log; @@ -642,19 +641,39 @@ public class AVMLockingServiceImpl implements AVMLockingService } // check for content manager role - we allow access to all managers within the same store - List children = fNodeService.getChildAssocs( - webProjectRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL); - for (ChildAssociationRef child : children) + // TODO as part of WCM refactor, consolidate with WebProject.getWebProjectUserRole + StringBuilder query = new StringBuilder(128); + query.append("+PARENT:\"").append(webProjectRef).append("\" "); + query.append("+TYPE:\"").append(WCMAppModel.TYPE_WEBUSER).append("\" "); + query.append("+@").append(NamespaceService.WCMAPP_MODEL_PREFIX).append("\\:username:\""); + query.append(user); + query.append("\""); + ResultSet resultSet = fSearchService.query( + new StoreRef(this.webProjectStore), + SearchService.LANGUAGE_LUCENE, + query.toString()); + List nodes = resultSet.getNodeRefs(); + + if (nodes.size() == 1) { - NodeRef childRef = child.getChildRef(); - if (fNodeService.getProperty(childRef, WCMAppModel.PROP_WEBUSERNAME).equals(user) && - fNodeService.getProperty(childRef, WCMAppModel.PROP_WEBUSERROLE).equals(ROLE_CONTENT_MANAGER)) + String userrole = (String)fNodeService.getProperty(nodes.get(0), WCMAppModel.PROP_WEBUSERROLE); + if (ROLE_CONTENT_MANAGER.equals(userrole)) { - if (logger.isDebugEnabled()) - logger.debug(" GRANTED: Store match and user is ContentManager role in webproject."); - return true; + if (logger.isDebugEnabled()) + { + logger.debug("GRANTED: Store match and user is ContentManager role in webproject."); + } + return true; } } + else if (nodes.size() == 0) + { + logger.warn("hasAccess: user role not found for " + user); + } + else + { + logger.warn("hasAccess: more than one user role found for " + user); + } // finally check the owners of the lock against the specified authority List owners = lock.getOwners(); diff --git a/source/java/org/alfresco/repo/content/transform/RemoteOpenOfficeContentTransformer.java b/source/java/org/alfresco/repo/content/transform/RemoteOpenOfficeContentTransformer.java new file mode 100644 index 0000000000..46619ac81b --- /dev/null +++ b/source/java/org/alfresco/repo/content/transform/RemoteOpenOfficeContentTransformer.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.content.transform; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import net.sf.jooreports.converter.DocumentFamily; +import net.sf.jooreports.converter.DocumentFormat; +import net.sf.jooreports.converter.DocumentFormatRegistry; +import net.sf.jooreports.converter.XmlDocumentFormatRegistry; +import net.sf.jooreports.openoffice.connection.OpenOfficeConnection; +import net.sf.jooreports.openoffice.connection.OpenOfficeException; +import net.sf.jooreports.openoffice.converter.StreamOpenOfficeDocumentConverter; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.content.transform.AbstractContentTransformer; +import org.alfresco.service.cmr.repository.ContentIOException; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.util.PropertyCheck; +import org.alfresco.util.TempFileProvider; +import org.springframework.core.io.DefaultResourceLoader; + +/** + * Makes use of the {@link http://sourceforge.net/projects/joott/JOOConverter} library to + * perform OpenOffice-drive conversions. + * + * @author Derek Hulley + * @author Juan David Zuluaga Arboleda + * @author Jared Ottley + * + */ +public class RemoteOpenOfficeContentTransformer extends AbstractContentTransformer +{ + private OpenOfficeConnection connection; + private StreamOpenOfficeDocumentConverter converter; + private String documentFormatsConfiguration; + private DocumentFormatRegistry formatRegistry; + + public RemoteOpenOfficeContentTransformer() + { + } + + public void setConnection(OpenOfficeConnection connection) + { + this.connection = connection; + } + + /** + * Set a non-default location from which to load the document format mappings. + * + * @param path a resource location supporting the file: or classpath: prefixes + */ + public void setDocumentFormatsConfiguration(String path) + { + this.documentFormatsConfiguration = path; + } + + public boolean isConnected() + { + return connection.isConnected(); + } + + @Override + public void register() + { + PropertyCheck.mandatory("OpenOfficeContentTransformer", "connection", connection); + + // load the document conversion configuration + if (documentFormatsConfiguration != null) + { + DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); + try + { + InputStream is = resourceLoader.getResource(documentFormatsConfiguration).getInputStream(); + formatRegistry = new XmlDocumentFormatRegistry(is); + } + catch (IOException e) + { + throw new AlfrescoRuntimeException( + "Unable to load document formats configuration file: " + documentFormatsConfiguration); + } + } + else + { + formatRegistry = new XmlDocumentFormatRegistry(); + } + + // set up the converter + converter = new StreamOpenOfficeDocumentConverter(connection); + + // Register + super.register(); + } + + /** + * @see DocumentFormatRegistry + */ + public double getReliability(String sourceMimetype, String targetMimetype) + { + if (!isConnected()) + { + // The connection management is must take care of this + return 0.0; + } + + // there are some conversions that fail, despite the converter believing them possible + if (targetMimetype.equals(MimetypeMap.MIMETYPE_XHTML)) + { + return 0.0; + } + else if (targetMimetype.equals(MimetypeMap.MIMETYPE_WORDPERFECT)) + { + return 0.0; + } + + MimetypeService mimetypeService = getMimetypeService(); + String sourceExtension = mimetypeService.getExtension(sourceMimetype); + String targetExtension = mimetypeService.getExtension(targetMimetype); + // query the registry for the source format + DocumentFormat sourceFormat = formatRegistry.getFormatByFileExtension(sourceExtension); + if (sourceFormat == null) + { + // no document format + return 0.0; + } + // query the registry for the target format + DocumentFormat targetFormat = formatRegistry.getFormatByFileExtension(targetExtension); + if (targetFormat == null) + { + // no document format + return 0.0; + } + + // get the family of the target document + DocumentFamily sourceFamily = sourceFormat.getFamily(); + // does the format support the conversion + if (!targetFormat.isExportableFrom(sourceFamily)) + { + // unable to export from source family of documents to the target format + return 0.0; + } + else + { + return 1.0; + } + } + + protected void transformInternal( + ContentReader reader, + ContentWriter writer, + Map options) throws Exception + { + String sourceMimetype = getMimetype(reader); + String targetMimetype = getMimetype(writer); + + MimetypeService mimetypeService = getMimetypeService(); + String sourceExtension = mimetypeService.getExtension(sourceMimetype); + String targetExtension = mimetypeService.getExtension(targetMimetype); + // query the registry for the source format + DocumentFormat sourceFormat = formatRegistry.getFormatByFileExtension(sourceExtension); + if (sourceFormat == null) + { + // source format is not recognised + throw new ContentIOException("No OpenOffice document format for source extension: " + sourceExtension); + } + // query the registry for the target format + DocumentFormat targetFormat = formatRegistry.getFormatByFileExtension(targetExtension); + if (targetFormat == null) + { + // target format is not recognised + throw new ContentIOException("No OpenOffice document format for target extension: " + targetExtension); + } + // get the family of the target document + DocumentFamily sourceFamily = sourceFormat.getFamily(); + // does the format support the conversion + if (!targetFormat.isExportableFrom(sourceFamily)) + { + throw new ContentIOException( + "OpenOffice conversion not supported: \n" + + " reader: " + reader + "\n" + + " writer: " + writer); + } + + // create temporary files to convert from and to + File tempFromFile = TempFileProvider.createTempFile( + "OpenOfficeContentTransformer-source-", + "." + sourceExtension); + File tempToFile = TempFileProvider.createTempFile( + "OpenOfficeContentTransformer-target-", + "." + targetExtension); + // download the content from the source reader + reader.getContent(tempFromFile); + + try + { + converter.convert(tempFromFile, sourceFormat, tempToFile, targetFormat); + // conversion success + } + catch (OpenOfficeException e) + { + throw new ContentIOException("OpenOffice server conversion failed: \n" + + " reader: " + reader + "\n" + + " writer: " + writer + "\n" + + " from file: " + tempFromFile + "\n" + + " to file: " + tempToFile, + e); + } + + // upload the temp output to the writer given us + writer.putContent(tempToFile); + } +} diff --git a/source/java/org/alfresco/repo/deploy/DeploymentServiceImpl.java b/source/java/org/alfresco/repo/deploy/DeploymentServiceImpl.java index 8986e1ad3e..370454b1e6 100644 --- a/source/java/org/alfresco/repo/deploy/DeploymentServiceImpl.java +++ b/source/java/org/alfresco/repo/deploy/DeploymentServiceImpl.java @@ -877,7 +877,7 @@ public class DeploymentServiceImpl implements DeploymentService } report.add(event); String storeName = srcPath.substring(0, srcPath.indexOf(':')); - System.out.println(storeName); + if (version < 0) { version = fAVMService.createSnapshot(storeName, null, null).get(storeName); @@ -908,15 +908,28 @@ public class DeploymentServiceImpl implements DeploymentService callback.eventOccurred(event); } - if (service != null) + if (service != null && ticket != null) { + // TODO MER - Consider what happens if abort throws an exception itself, then we loose e? service.abort(ticket); } throw new AVMException("Deployment to: " + target + " failed.", e); } } - + /** + * deployDirectoryPush + * Compares the source and destination listings and updates report with update events required to make + * dest similar to src. + * @param service + * @param ticket + * @param report + * @param callbacks + * @param version + * @param srcPath + * @param dstPath + * @param matcher + */ private void deployDirectoryPush(DeploymentReceiverService service, String ticket, DeploymentReport report, List callbacks, int version, @@ -926,9 +939,12 @@ public class DeploymentServiceImpl implements DeploymentService List dstListing = service.getListing(ticket, dstPath); Iterator srcIter = srcListing.values().iterator(); Iterator dstIter = dstListing.iterator(); + // Here with two sorted directory listings AVMNodeDescriptor src = null; FileDescriptor dst = null; - while (srcIter.hasNext() || dstIter.hasNext()) + + // Step through both directory listings + while (srcIter.hasNext() || dstIter.hasNext() || src != null || dst != null) { if (src == null) { @@ -944,7 +960,11 @@ public class DeploymentServiceImpl implements DeploymentService dst = dstIter.next(); } } - // This means no entry on src so delete. + if (fgLogger.isDebugEnabled()) + { + fgLogger.debug("comparing src:" + src + " dst:"+ dst); + } + // This means no entry on src so delete what is on dst. if (src == null) { String newDstPath = extendPath(dstPath, dst.getName()); @@ -980,9 +1000,12 @@ public class DeploymentServiceImpl implements DeploymentService src = null; continue; } + + // Here with src and dst containing something int diff = src.getName().compareToIgnoreCase(dst.getName()); if (diff < 0) { + // src is less than dst - must be new content in src if (!excluded(matcher, src.getPath(), null)) { copy(service, ticket, report, callbacks, version, src, dstPath, matcher); @@ -992,6 +1015,7 @@ public class DeploymentServiceImpl implements DeploymentService } if (diff == 0) { + // src and dst have same file name if (src.getGuid().equals(dst.getGUID())) { src = null; diff --git a/source/java/org/alfresco/repo/usage/UsageDelta.java b/source/java/org/alfresco/repo/domain/UsageDelta.java similarity index 97% rename from source/java/org/alfresco/repo/usage/UsageDelta.java rename to source/java/org/alfresco/repo/domain/UsageDelta.java index 4f70145266..9f38373b99 100644 --- a/source/java/org/alfresco/repo/usage/UsageDelta.java +++ b/source/java/org/alfresco/repo/domain/UsageDelta.java @@ -22,7 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.usage; +package org.alfresco.repo.domain; import org.alfresco.repo.domain.Node; diff --git a/source/java/org/alfresco/repo/usage/hibernate/HibernateUsageDeltaDAO.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateUsageDeltaDAO.java similarity index 70% rename from source/java/org/alfresco/repo/usage/hibernate/HibernateUsageDeltaDAO.java rename to source/java/org/alfresco/repo/domain/hibernate/HibernateUsageDeltaDAO.java index fe7aa9f25f..ba66aa706f 100644 --- a/source/java/org/alfresco/repo/usage/hibernate/HibernateUsageDeltaDAO.java +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateUsageDeltaDAO.java @@ -22,17 +22,21 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.usage.hibernate; +package org.alfresco.repo.domain.hibernate; import java.util.HashSet; import java.util.List; import java.util.Set; import org.alfresco.repo.domain.Node; +import org.alfresco.repo.domain.UsageDelta; +import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.transaction.TransactionalDao; -import org.alfresco.repo.usage.UsageDelta; import org.alfresco.repo.usage.UsageDeltaDAO; +import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.util.GUID; +import org.alfresco.util.ParameterCheck; import org.hibernate.Query; import org.hibernate.Session; import org.springframework.orm.hibernate3.HibernateCallback; @@ -44,13 +48,19 @@ import org.springframework.orm.hibernate3.support.HibernateDaoSupport; */ public class HibernateUsageDeltaDAO extends HibernateDaoSupport implements UsageDeltaDAO, TransactionalDao { - private static final String QUERY_GET_DELTAS = "usage.GetDeltas"; +// private static final String QUERY_GET_DELTAS = "usage.GetDeltas"; private static final String QUERY_GET_TOTAL_DELTA_SIZE = "usage.GetTotalDeltaSize"; private static final String QUERY_GET_USAGE_DELTA_NODES = "usage.GetUsageDeltaNodes"; + private static final String QUERY_DELETE_DELTAS_FOR_NODE = "usage.DeleteUsageDeltasForNode"; /** a uuid identifying this unique instance */ private final String uuid; + private NodeDaoService nodeDaoService; + public void setNodeDaoService(NodeDaoService nodeDaoService) + { + this.nodeDaoService = nodeDaoService; + } /** * @@ -119,34 +129,48 @@ public class HibernateUsageDeltaDAO extends HibernateDaoSupport implements Usage { getSession().flush(); } + + private Node getNodeNotNull(NodeRef nodeRef) throws InvalidNodeRefException + { + ParameterCheck.mandatory("nodeRef", nodeRef); + + Node unchecked = nodeDaoService.getNode(nodeRef); + if (unchecked == null) + { + throw new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef); + } + return unchecked; + } + public int deleteDeltas(NodeRef nodeRef) + { + Node node = getNodeNotNull(nodeRef); + return deleteDeltas(node.getId()); + } + @SuppressWarnings("unchecked") - public int deleteDeltas(final Node node) + public int deleteDeltas(final Long nodeId) { HibernateCallback callback = new HibernateCallback() { public Object doInHibernate(Session session) { - Query query = session.getNamedQuery(QUERY_GET_DELTAS); - query.setParameter("node", node); - return query.list(); + Query query = session.getNamedQuery(QUERY_DELETE_DELTAS_FOR_NODE); + query.setParameter("nodeId", nodeId); + return query.executeUpdate(); } }; // execute - List queryResults = (List)getHibernateTemplate().execute(callback); + Integer delCount = (Integer) getHibernateTemplate().execute(callback); - for (UsageDelta usageDelta : queryResults) - { - getHibernateTemplate().delete(usageDelta); - } - - return queryResults.size(); + return delCount.intValue(); } @SuppressWarnings("unchecked") - public long getTotalDeltaSize(final Node node) + public long getTotalDeltaSize(NodeRef nodeRef) { + final Node node = getNodeNotNull(nodeRef); HibernateCallback callback = new HibernateCallback() { public Object doInHibernate(Session session) @@ -163,14 +187,21 @@ public class HibernateUsageDeltaDAO extends HibernateDaoSupport implements Usage return (queryResult == null ? 0 : queryResult); } - public void insertDelta(UsageDelta deltaInfo) + public void insertDelta(NodeRef usageNodeRef, long deltaSize) { + Node node = getNodeNotNull(usageNodeRef); + + UsageDelta delta = new UsageDeltaImpl(); + // delta properties + delta.setNode(node); + delta.setDeltaSize(deltaSize); + // Save - getSession().save(deltaInfo); + getSession().save(delta); } @SuppressWarnings("unchecked") - public Set getUsageDeltaNodes() + public Set getUsageDeltaNodes() { HibernateCallback callback = new HibernateCallback() { @@ -183,10 +214,10 @@ public class HibernateUsageDeltaDAO extends HibernateDaoSupport implements Usage }; // execute read-only tx List queryResults = (List)getHibernateTemplate().execute(callback); - Set results = new HashSet(queryResults.size()); + Set results = new HashSet(queryResults.size(), 1.0F); for (Node node : queryResults) { - results.add(node); + results.add(node.getNodeRef()); } return results; } diff --git a/source/java/org/alfresco/repo/domain/hibernate/UsageDelta.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/UsageDelta.hbm.xml index 29247d9e71..e332309765 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/UsageDelta.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/UsageDelta.hbm.xml @@ -16,8 +16,8 @@ - @@ -63,7 +63,7 @@ select distinct usage_delta.node from - org.alfresco.repo.usage.hibernate.UsageDeltaImpl as usage_delta + org.alfresco.repo.domain.hibernate.UsageDeltaImpl as usage_delta @@ -71,9 +71,17 @@ select usage_delta from - org.alfresco.repo.usage.hibernate.UsageDeltaImpl as usage_delta + org.alfresco.repo.domain.hibernate.UsageDeltaImpl as usage_delta where usage_delta.node = :node + + delete + from + org.alfresco.repo.domain.hibernate.UsageDeltaImpl as usage + where + usage.node.id = :nodeId + + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/usage/hibernate/UsageDeltaImpl.java b/source/java/org/alfresco/repo/domain/hibernate/UsageDeltaImpl.java similarity index 96% rename from source/java/org/alfresco/repo/usage/hibernate/UsageDeltaImpl.java rename to source/java/org/alfresco/repo/domain/hibernate/UsageDeltaImpl.java index f8fb325070..de761c950e 100644 --- a/source/java/org/alfresco/repo/usage/hibernate/UsageDeltaImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/UsageDeltaImpl.java @@ -22,10 +22,10 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.usage.hibernate; +package org.alfresco.repo.domain.hibernate; import org.alfresco.repo.domain.Node; -import org.alfresco.repo.usage.UsageDelta; +import org.alfresco.repo.domain.UsageDelta; /** * Usage Delta Implementation diff --git a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java index b862e80793..bb08b39f26 100644 --- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java @@ -684,7 +684,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements { logger.debug("Deleting usage deltas of node (if any)" + node.getId()); } - usageDeltaDao.deleteDeltas(node); + usageDeltaDao.deleteDeltas(node.getId()); // update the node status NodeRef nodeRef = node.getNodeRef(); diff --git a/source/java/org/alfresco/repo/node/index/MissingContentReindexComponent.java b/source/java/org/alfresco/repo/node/index/MissingContentReindexComponent.java index 6d339e5d31..45064ae9bf 100644 --- a/source/java/org/alfresco/repo/node/index/MissingContentReindexComponent.java +++ b/source/java/org/alfresco/repo/node/index/MissingContentReindexComponent.java @@ -123,7 +123,7 @@ public class MissingContentReindexComponent extends AbstractReindexComponent return null; } }; - transactionService.getRetryingTransactionHelper().doInTransaction(reindexWork); + transactionService.getRetryingTransactionHelper().doInTransaction(reindexWork, true); count++; // check if we have to break out if (isShuttingDown()) diff --git a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java index fece58333a..2741f2682f 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java @@ -354,13 +354,8 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService public List getRules(NodeRef nodeRef, boolean includeInherited, String ruleTypeName) { List rules = new ArrayList(); - - // Extra check of CONSUMER permission was added to rule selection, - // to prevent Access Denied Exception due to the bug: - // https://issues.alfresco.com/browse/ETWOTWO-438 - if (this.runtimeNodeService.exists(nodeRef) == true && checkNodeType(nodeRef) == true && - permissionService.hasPermission(nodeRef, PermissionService.CONSUMER) == AccessStatus.ALLOWED) + if (this.runtimeNodeService.exists(nodeRef) == true && checkNodeType(nodeRef) == true) { if (includeInherited == true && this.runtimeNodeService.hasAspect(nodeRef, RuleModel.ASPECT_IGNORE_INHERITED_RULES) == false) { @@ -375,7 +370,12 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService } } - if (this.runtimeNodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true) + // Extra check of CONSUMER permission was added to rule selection, + // to prevent Access Denied Exception due to the bug: + // https://issues.alfresco.com/browse/ETWOTWO-438 + + if (this.runtimeNodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true && + permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.ALLOWED) { NodeRef ruleFolder = getSavedRuleFolderRef(nodeRef); if (ruleFolder != null) diff --git a/source/java/org/alfresco/repo/tenant/MultiTDemoSystemTest.java b/source/java/org/alfresco/repo/tenant/MultiTDemoSystemTest.java new file mode 100755 index 0000000000..b417fb8622 --- /dev/null +++ b/source/java/org/alfresco/repo/tenant/MultiTDemoSystemTest.java @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2005-2008 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.tenant; + +import java.io.PrintWriter; +import java.io.Serializable; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import junit.framework.TestCase; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ApplicationModel; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.ContentWriter; +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.CategoryService; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.cmr.security.OwnableService; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.ApplicationContextHelper; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationContext; + +public class MultiTDemoSystemTest extends TestCase +{ + private static Log logger = LogFactory.getLog(MultiTDemoSystemTest.class); + + private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + private NodeService nodeService; + private AuthenticationService authenticationService; + private PersonService personService; + private SearchService searchService; + private ContentService contentService; + private PermissionService permissionService; + private OwnableService ownableService; + private TenantAdminService tenantAdminService; + private TenantService tenantService; + private AuthorityService authorityService; + private CategoryService categoryService; + + public static final String TEST_TENANT_DOMAIN1 = "yyy.com"; + public static final String TEST_TENANT_DOMAIN2 = "zzz.com"; + + private static List tenants; + + static { + tenants = new ArrayList(2); + tenants.add(TEST_TENANT_DOMAIN1); + tenants.add(TEST_TENANT_DOMAIN2); + } + + public static final String ROOT_DIR = "./tenantstores"; + + public static final String TEST_ADMIN_BASENAME = "admin"; + public static final String TEST_ADMIN_PASSWORD = "admin"; + + public static final String TEST_USER1 = "alice"; + public static final String TEST_USER2 = "bob"; + public static final String TEST_USER3 = "eve"; + + + public static StoreRef SPACES_STORE = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"); + + + public MultiTDemoSystemTest() + { + } + + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + nodeService = (NodeService) ctx.getBean("NodeService"); + authenticationService = (AuthenticationService) ctx.getBean("AuthenticationService"); + tenantAdminService = (TenantAdminService) ctx.getBean("tenantAdminService"); + tenantService = (TenantService) ctx.getBean("tenantService"); + personService = (PersonService) ctx.getBean("PersonService"); + searchService = (SearchService) ctx.getBean("SearchService"); + contentService = (ContentService) ctx.getBean("ContentService"); + permissionService = (PermissionService) ctx.getBean("PermissionService"); + ownableService = (OwnableService) ctx.getBean("OwnableService"); + authorityService = (AuthorityService) ctx.getBean("AuthorityService"); + categoryService = (CategoryService) ctx.getBean("CategoryService"); + + AuthenticationUtil.setCurrentUser(AuthenticationUtil.getSystemUserName()); // force, to clear real user from previous test (runAs issue ?) + } + + @Override + protected void tearDown() throws Exception + { + super.tearDown(); + } + + + public void testCreateTenants() throws Throwable + { + logger.info("Create tenants"); + + try + { + for (final String tenantDomain : tenants) + { + // create tenants (if not already created) + AuthenticationUtil.runAs(new RunAsWork() + { + public Object doWork() throws Exception + { + if (! tenantAdminService.existsTenant(tenantDomain)) + { + //tenantAdminService.createTenant(tenantDomain, TEST_ADMIN_PASSWORD.toCharArray(), ROOT_DIR + "/" + tenantDomain); + tenantAdminService.createTenant(tenantDomain, TEST_ADMIN_PASSWORD.toCharArray(), null); // use default root dir + + logger.info("Created tenant " + tenantDomain); + } + + return null; + } + }, AuthenticationUtil.getSystemUserName()); + } + } + catch (Throwable t) + { + StringWriter stackTrace = new StringWriter(); + t.printStackTrace(new PrintWriter(stackTrace)); + System.err.println(stackTrace.toString()); + throw t; + } + } + + public void testCreateUsers() throws Throwable + { + logger.info("Create demo users"); + + try + { + for (final String tenantDomain : tenants) + { + String tenantAdminName = tenantService.getDomainUser(TenantService.ADMIN_BASENAME, tenantDomain); + + AuthenticationUtil.runAs(new RunAsWork() + { + public Object doWork() throws Exception + { + createUser(TEST_USER1, tenantDomain, "welcome"); + + createUser(TEST_USER2, tenantDomain, "welcome"); + + if (tenantDomain.equals(TEST_TENANT_DOMAIN2)) + { + createUser(TEST_USER3, tenantDomain, "welcome"); + } + + return null; + } + }, tenantAdminName); + + } + } + catch (Throwable t) + { + StringWriter stackTrace = new StringWriter(); + t.printStackTrace(new PrintWriter(stackTrace)); + System.err.println(stackTrace.toString()); + throw t; + } + } + + public void testCreateGroups() + { + logger.info("Create demo groups"); + + for (final String tenantDomain : tenants) + { + String tenantAdminName = tenantService.getDomainUser("admin", tenantDomain); + + AuthenticationUtil.runAs(new RunAsWork() + { + public Object doWork() throws Exception + { + createGroup("GrpA-"+tenantDomain, null); + createGroup("SubGrpA-"+tenantDomain, "GrpA-"+tenantDomain); + + createGroup("GrpB-"+tenantDomain, null); + createGroup("SubGrpB-"+tenantDomain, "GrpB-"+tenantDomain); + + if (tenantDomain.equals(TEST_TENANT_DOMAIN2)) + { + createGroup("GrpC-"+tenantDomain, null); + createGroup("SubGrpC-"+tenantDomain, "GrpC-"+tenantDomain); + } + + return null; + } + }, tenantAdminName); + + } + } + + public void testCreateCategories() + { + logger.info("Create demo categories"); + + for (final String tenantDomain : tenants) + { + String tenantAdminName = tenantService.getDomainUser(TenantService.ADMIN_BASENAME, tenantDomain); + + AuthenticationUtil.runAs(new RunAsWork() + { + public Object doWork() throws Exception + { + NodeRef catRef = createCategory(SPACES_STORE, null, "CatA", "CatA-"+tenantDomain); + createCategory(SPACES_STORE, catRef, "SubCatA", "SubCatA-"+tenantDomain); // ignore return + + catRef = createCategory(SPACES_STORE, null, "CatB", "CatB-"+tenantDomain); + createCategory(SPACES_STORE, catRef, "SubCatB", "SubCatB-"+tenantDomain); // ignore return + + if (tenantDomain.equals(TEST_TENANT_DOMAIN2)) + { + catRef = createCategory(SPACES_STORE, null, "CatC", "CatC-"+tenantDomain); + createCategory(SPACES_STORE, catRef, "SubCatC", "SubCatC-"+tenantDomain); // ignore return + } + + return null; + } + }, tenantAdminName); + + } + } + + public void testCreateFolders() + { + logger.info("Create demo folders"); + + List users = new ArrayList(3); + users.add(TEST_USER1); + users.add(TEST_USER2); + users.add(TEST_USER3); + + for (final String tenantDomain : tenants) + { + for (String baseUserName : users) + { + if ((! baseUserName.equals(TEST_USER3)) || (tenantDomain.equals(TEST_TENANT_DOMAIN2))) + { + final String tenantUserName = tenantService.getDomainUser(baseUserName, tenantDomain); + + AuthenticationUtil.runAs(new RunAsWork() + { + public Object doWork() throws Exception + { + NodeRef homeSpaceRef = getHomeSpaceFolderNode(tenantUserName); + + NodeRef folderRef = createFolderNode(homeSpaceRef, "myfolder1"); + createFolderNode(folderRef, "mysubfolder1"); // ignore return + + folderRef = createFolderNode(homeSpaceRef, "myfolder2"); + createFolderNode(folderRef, "mysubfolder2"); // ignore return + + if (tenantDomain.equals(TEST_TENANT_DOMAIN2)) + { + folderRef = createFolderNode(homeSpaceRef, "myfolder3"); + createFolderNode(folderRef, "mysubfolder3"); // ignore return + } + + return null; + } + }, tenantUserName); + } + } + } + } + + public void testCreateUserContent() + { + logger.info("Create demo content"); + + List users = new ArrayList(3); + users.add(TEST_USER1); + users.add(TEST_USER2); + users.add(TEST_USER3); + + for (final String tenantDomain : tenants) + { + for (String baseUserName : users) + { + if ((! baseUserName.equals(TEST_USER3)) || (tenantDomain.equals(TEST_TENANT_DOMAIN2))) + { + final String tenantUserName = tenantService.getDomainUser(baseUserName, tenantDomain); + + AuthenticationUtil.runAs(new RunAsWork() + { + public Object doWork() throws Exception + { + NodeRef homeSpaceRef = getHomeSpaceFolderNode(tenantUserName); + addTextContent(homeSpaceRef, tenantUserName+" quick brown fox.txt", "The quick brown fox jumps over the lazy dog (tenant " + tenantDomain + ")"); + + if (tenantDomain.equals(TEST_TENANT_DOMAIN2)) + { + addTextContent(homeSpaceRef, tenantUserName+" quick brown fox ANO.txt", "The quick brown fox jumps over the lazy dog ANO (tenant " + tenantDomain + ")"); + } + + return null; + } + }, tenantUserName); + } + } + } + } + + + private void createGroup(String shortName, String parentShortName) + { + // create new Group using authority Service + String groupName = this.authorityService.getName(AuthorityType.GROUP, shortName); + if (this.authorityService.authorityExists(groupName) == false) + { + String parentGroupName = null; + if (parentShortName != null) + { + parentGroupName = this.authorityService.getName(AuthorityType.GROUP, parentShortName); + if (this.authorityService.authorityExists(parentGroupName) == false) + { + logger.warn("Parent group does not exist: " + parentShortName); + return; + } + } + + this.authorityService.createAuthority(AuthorityType.GROUP, parentGroupName, shortName); + + } + else + { + logger.warn("Group already exists: " + shortName); + } + } + + + private void createUser(String baseUserName, String tenantDomain, String password) + { + String userName = tenantService.getDomainUser(baseUserName, tenantDomain); + + if (! this.authenticationService.authenticationExists(userName)) + { + NodeRef baseHomeFolder = getUserHomesNodeRef(SPACES_STORE); + + // Create the users home folder + NodeRef homeFolder = createHomeSpaceFolderNode( + baseHomeFolder, + baseUserName, + userName); + + // Create the authentication + this.authenticationService.createAuthentication(userName, password.toCharArray()); + + // Create the person + Map personProperties = new HashMap(); + personProperties.put(ContentModel.PROP_USERNAME, userName); + personProperties.put(ContentModel.PROP_HOMEFOLDER, homeFolder); + personProperties.put(ContentModel.PROP_FIRSTNAME, baseUserName); + personProperties.put(ContentModel.PROP_LASTNAME, baseUserName+"-"+tenantDomain); // add domain suffix here for demo only + personProperties.put(ContentModel.PROP_EMAIL, userName); + + NodeRef newPerson = this.personService.createPerson(personProperties); + + // ensure the user can access their own Person object + this.permissionService.setPermission(newPerson, userName, permissionService.getAllPermission(), true); + + logger.info("Created user " + userName); + } + } + + private NodeRef getUserHomesNodeRef(StoreRef storeRef) + { + // get the users' home location + String path = "/app:company_home/app:user_homes"; + + ResultSet rs = this.searchService.query(storeRef, SearchService.LANGUAGE_XPATH, path); + + NodeRef usersHomeNodeRef = null; + if (rs.length() == 0) + { + throw new AlfrescoRuntimeException("Cannot find user homes location: " + path); + } + else + { + usersHomeNodeRef = rs.getNodeRef(0); + } + return usersHomeNodeRef; + } + + private NodeRef createFolderNode(NodeRef parentFolderNodeRef, String nameValue) + { + if (nameValue != null) + { + Map folderProps = new HashMap(); + folderProps.put(ContentModel.PROP_NAME, nameValue); + + return this.nodeService.createNode( + parentFolderNodeRef, + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, nameValue), + ContentModel.TYPE_FOLDER, + folderProps).getChildRef(); + } + + return null; + } + + private NodeRef createCategory(StoreRef storeRef, NodeRef parentCategoryRef, String name, String description) + { + // create category using categoryservice + NodeRef ref; + if (parentCategoryRef == null) + { + ref = this.categoryService.createRootCategory(storeRef, ContentModel.ASPECT_GEN_CLASSIFIABLE, name); + } + else + { + ref = categoryService.createCategory(parentCategoryRef, name); + } + + // apply the titled aspect - for description + Map titledProps = new HashMap(1, 1.0f); + titledProps.put(ContentModel.PROP_DESCRIPTION, description); + this.nodeService.addAspect(ref, ContentModel.ASPECT_TITLED, titledProps); + + return ref; + } + + private NodeRef createHomeSpaceFolderNode(NodeRef folderNodeRef, String spaceName, String userName) + { + if (spaceName != null) + { + Map folderProps = new HashMap(); + folderProps.put(ContentModel.PROP_NAME, spaceName); + + NodeRef nodeRef = this.nodeService.createNode( + folderNodeRef, + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, spaceName), + ContentModel.TYPE_FOLDER, + folderProps).getChildRef(); + + // apply the uifacets aspect - icon and title props + Map uiFacetsProps = new HashMap(3); + uiFacetsProps.put(ApplicationModel.PROP_ICON, "space-icon-default"); + uiFacetsProps.put(ContentModel.PROP_TITLE, spaceName); + this.nodeService.addAspect(nodeRef, ApplicationModel.ASPECT_UIFACETS, uiFacetsProps); + + setupHomeSpacePermissions(nodeRef, userName); + + return nodeRef; + } + + return null; + } + + private void setupHomeSpacePermissions(NodeRef homeSpaceRef, String userName) + { + // Admin Authority has full permissions by default (automatic - set in the permission config) + // give full permissions to the new user + this.permissionService.setPermission(homeSpaceRef, userName, permissionService.getAllPermission(), true); + + // by default other users will only have GUEST access to the space contents + String permission = "Consumer"; + + if (permission != null && permission.length() != 0) + { + this.permissionService.setPermission(homeSpaceRef, permissionService.getAllAuthorities(), permission, true); + } + + // the new user is the OWNER of their own space and always has full permissions + this.ownableService.setOwner(homeSpaceRef, userName); + this.permissionService.setPermission(homeSpaceRef, permissionService.getOwnerAuthority(), permissionService.getAllPermission(), true); + + // now detach (if we did this first we could not set any permissions!) + this.permissionService.setInheritParentPermissions(homeSpaceRef, false); + } + + private NodeRef getHomeSpaceFolderNode(String userName) + { + return (NodeRef)this.nodeService.getProperty(personService.getPerson(userName), ContentModel.PROP_HOMEFOLDER); + } + + private void addTextContent(NodeRef spaceRef, String name, String textData) + { + Map contentProps = new HashMap(); + contentProps.put(ContentModel.PROP_NAME, name); + + ChildAssociationRef association = nodeService.createNode(spaceRef, + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name), + ContentModel.TYPE_CONTENT, + contentProps); + + NodeRef content = association.getChildRef(); + + // add titled aspect (for Web Client display) + Map titledProps = new HashMap(); + titledProps.put(ContentModel.PROP_TITLE, name); + titledProps.put(ContentModel.PROP_DESCRIPTION, name); + this.nodeService.addAspect(content, ContentModel.ASPECT_TITLED, titledProps); + + ContentWriter writer = contentService.getWriter(content, ContentModel.PROP_CONTENT, true); + + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.setEncoding("UTF-8"); + + writer.putContent(textData); + } + + + // comment-in to run from command line + public static void main(String args[]) + { + System.out.println(new Date()); + junit.textui.TestRunner.run(MultiTDemoSystemTest.class); + System.out.println(new Date()); + } + +} diff --git a/source/java/org/alfresco/repo/tenant/TenantService.java b/source/java/org/alfresco/repo/tenant/TenantService.java index 19fafedcfe..36355fcadb 100644 --- a/source/java/org/alfresco/repo/tenant/TenantService.java +++ b/source/java/org/alfresco/repo/tenant/TenantService.java @@ -47,30 +47,69 @@ public interface TenantService extends TenantBaseService public static final String ADMIN_BASENAME = "admin"; + /** + * @return the reference with the tenant-specific ID attached + */ public NodeRef getName(NodeRef nodeRef); + /** + * @return the reference with the tenant-specific ID attached + */ public NodeRef getName(NodeRef inNodeRef, NodeRef nodeRef); + /** + * @return the reference with the tenant-specific ID attached + */ public StoreRef getName(StoreRef storeRef); + /** + * @return the reference with the tenant-specific ID attached + */ public ChildAssociationRef getName(ChildAssociationRef childAssocRef); + /** + * @return the reference with the tenant-specific ID attached + */ public StoreRef getName(String username, StoreRef storeRef); + /** + * @return the reference with the tenant-specific ID attached + */ public QName getName(NodeRef inNodeRef, QName name); + /** + * @return the reference with the tenant-specific ID attached + */ public String getName(String name); + /** + * @return the reference without the tenant-specific ID attached + */ public QName getBaseName(QName name, boolean forceIfNonTenant); + /** + * @return the reference without the tenant-specific ID attached + */ public NodeRef getBaseName(NodeRef nodeRef); + /** + * @return the reference without the tenant-specific ID attached + */ public StoreRef getBaseName(StoreRef storeRef); + /** + * @return the reference without the tenant-specific ID attached + */ public ChildAssociationRef getBaseName(ChildAssociationRef childAssocRef); + /** + * @return the reference without the tenant-specific ID attached + */ public String getBaseName(String name); + /** + * @return the reference without the tenant-specific ID attached + */ public String getBaseName(String name, boolean forceIfNonTenant); public String getBaseNameUser(String name); diff --git a/source/java/org/alfresco/repo/usage/UsageDeltaDAO.java b/source/java/org/alfresco/repo/usage/UsageDeltaDAO.java index 8dd4e73857..d392531fa5 100644 --- a/source/java/org/alfresco/repo/usage/UsageDeltaDAO.java +++ b/source/java/org/alfresco/repo/usage/UsageDeltaDAO.java @@ -26,7 +26,7 @@ package org.alfresco.repo.usage; import java.util.Set; -import org.alfresco.repo.domain.Node; +import org.alfresco.service.cmr.repository.NodeRef; /** * The interface to persist usage delta information. @@ -37,20 +37,21 @@ public interface UsageDeltaDAO /** * Create a usage delta entry. * - * @param deltaInfo + * @param deltaSize the size change */ - public void insertDelta(UsageDelta deltaInfo); + public void insertDelta(NodeRef usageNodeRef, long deltaSize); /** * Get the total delta size for a node. * - * @param node - * @return sum of delta sizes (in bytes) - can be +ve or -ve + * @param nodeRef the node reference + * @return sum of delta sizes (in bytes) - can be +ve or -ve */ - public long getTotalDeltaSize(Node node); + public long getTotalDeltaSize(NodeRef usageNodeRef); + public Set getUsageDeltaNodes(); - public Set getUsageDeltaNodes(); + public int deleteDeltas(NodeRef nodeRef); - public int deleteDeltas(Node node); + public int deleteDeltas(Long nodeId); } diff --git a/source/java/org/alfresco/repo/usage/UsageServiceImpl.java b/source/java/org/alfresco/repo/usage/UsageServiceImpl.java index b734b83f91..3614ffe776 100644 --- a/source/java/org/alfresco/repo/usage/UsageServiceImpl.java +++ b/source/java/org/alfresco/repo/usage/UsageServiceImpl.java @@ -24,80 +24,43 @@ */ package org.alfresco.repo.usage; -import java.util.HashSet; import java.util.Set; -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.node.db.NodeDaoService; -import org.alfresco.repo.usage.hibernate.UsageDeltaImpl; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.usage.UsageService; -import org.alfresco.util.ParameterCheck; /** * The implementation of the UsageService for tracking usages. * + * @author Jan Vonka + * @since 2.9 */ public class UsageServiceImpl implements UsageService { private UsageDeltaDAO usageDeltaDao; - private NodeDaoService nodeDaoService; public void setUsageDeltaDao(UsageDeltaDAO usageDeltaDao) { this.usageDeltaDao = usageDeltaDao; } - public void setNodeDaoService(NodeDaoService nodeDaoService) - { - this.nodeDaoService = nodeDaoService; - } - - public void insertDelta(NodeRef usageNodeRef, long deltaSize) { - UsageDelta delta = new UsageDeltaImpl(); - - // delta properties - delta.setNode(getNodeNotNull(usageNodeRef)); - delta.setDeltaSize(deltaSize); - - usageDeltaDao.insertDelta(delta); + usageDeltaDao.insertDelta(usageNodeRef, deltaSize); } public long getTotalDeltaSize(NodeRef usageNodeRef) { - return usageDeltaDao.getTotalDeltaSize(getNodeNotNull(usageNodeRef)); + return usageDeltaDao.getTotalDeltaSize(usageNodeRef); } public Set getUsageDeltaNodes() { - Set nodes = usageDeltaDao.getUsageDeltaNodes(); - - // convert nodes to nodeRefs (tenant-specific) - Set results = new HashSet(nodes.size()); - for (Node node : nodes) - { - results.add(node.getNodeRef()); - } - return results; + return usageDeltaDao.getUsageDeltaNodes(); } public int deleteDeltas(NodeRef usageNodeRef) { - return usageDeltaDao.deleteDeltas(getNodeNotNull(usageNodeRef)); - } - - private Node getNodeNotNull(NodeRef nodeRef) throws InvalidNodeRefException - { - ParameterCheck.mandatory("nodeRef", nodeRef); - - Node unchecked = nodeDaoService.getNode(nodeRef); - if (unchecked == null) - { - throw new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef); - } - return unchecked; + return usageDeltaDao.deleteDeltas(usageNodeRef); } } diff --git a/source/java/org/alfresco/service/cmr/usage/UsageService.java b/source/java/org/alfresco/service/cmr/usage/UsageService.java index 6c7c7c66c5..76f25570cb 100644 --- a/source/java/org/alfresco/service/cmr/usage/UsageService.java +++ b/source/java/org/alfresco/service/cmr/usage/UsageService.java @@ -33,6 +33,8 @@ import org.alfresco.service.cmr.repository.NodeRef; /** * The public API by which applications can create usage delta entries. * + * @author Jan Vonka + * @since 2.9 */ @PublicService public interface UsageService