diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index b8aa3cb7d2..cb97dc6ae5 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -811,15 +811,9 @@ - + - 5 - - - 20 - - - 60 + 2 diff --git a/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java index bdd2c99006..e8650f2cac 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java @@ -2117,7 +2117,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa * @param sess Server session * @param tree Tree connection * @param file Network file details - * @param siz New file length + * @param size New file length * @exception java.io.IOException The exception description. */ public void truncateFile(SrvSession sess, TreeConnection tree, NetworkFile file, long size) throws IOException diff --git a/source/java/org/alfresco/repo/domain/Node.java b/source/java/org/alfresco/repo/domain/Node.java index bbd3fec546..3983a97ac7 100644 --- a/source/java/org/alfresco/repo/domain/Node.java +++ b/source/java/org/alfresco/repo/domain/Node.java @@ -24,7 +24,6 @@ */ package org.alfresco.repo.domain; -import java.util.Collection; import java.util.Map; import java.util.Set; @@ -71,8 +70,6 @@ public interface Node public Set getAspects(); -// public Collection getParentAssocs(); - public Map getProperties(); public DbAccessControlList getAccessControlList(); diff --git a/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java b/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java index f08a39c13e..655da3ccb1 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java @@ -153,19 +153,6 @@ public class NodeImpl extends LifecycleAdapter implements Node, Serializable return getUuid().hashCode(); } -// @Override -// public boolean onDelete(Session session) throws CallbackException -// { -// // check if there is an access control list -// DbAccessControlList acl = getAccessControlList(); -// if (acl != null) -// { -// session.delete(acl); -// } -// return NO_VETO; -// } -// - public Long getId() { return id; diff --git a/source/java/org/alfresco/repo/search/DocumentNavigator.java b/source/java/org/alfresco/repo/search/DocumentNavigator.java index 2ad838a95e..4e856de28d 100644 --- a/source/java/org/alfresco/repo/search/DocumentNavigator.java +++ b/source/java/org/alfresco/repo/search/DocumentNavigator.java @@ -559,4 +559,9 @@ public class DocumentNavigator extends DefaultNavigator implements NamedAccessNa QName nodeTypeQName = nodeService.getType(nodeRef); return dictionaryService.isSubClass(nodeTypeQName, typeQName); } + + public Boolean hasAspect(NodeRef nodeRef, QName typeQName) + { + return nodeService.hasAspect(nodeRef, typeQName); + } } diff --git a/source/java/org/alfresco/repo/search/NodeServiceXPath.java b/source/java/org/alfresco/repo/search/NodeServiceXPath.java index 12a59e33aa..ce7ee2b2d4 100644 --- a/source/java/org/alfresco/repo/search/NodeServiceXPath.java +++ b/source/java/org/alfresco/repo/search/NodeServiceXPath.java @@ -225,8 +225,7 @@ public class NodeServiceXPath extends BaseXPath } /** - * A boolean function to determine if a node type is a subtype of another - * type + * A boolean function to determine if a node type is a subtype of another type */ static class SubTypeOf implements Function { @@ -278,6 +277,59 @@ public class NodeServiceXPath extends BaseXPath } } + /** + * A boolean function to determine if a node has a given aspect + */ + static class HasAspect implements Function + { + public Object call(Context context, List args) throws FunctionCallException + { + if (args.size() != 1) + { + throw new FunctionCallException("hasAspect() requires one argument: hasAspect(QName typeQName)"); + } + return evaluate(context.getNodeSet(), args.get(0), context.getNavigator()); + } + + public Object evaluate(List nodes, Object qnameObj, Navigator nav) + { + if (nodes.size() != 1) + { + return false; + } + // resolve the qname of the type we are checking for + String qnameStr = StringFunction.evaluate(qnameObj, nav); + if (qnameStr.equals("*")) + { + return true; + } + QName typeQName; + + if (qnameStr.startsWith("{")) + { + typeQName = QName.createQName(qnameStr); + } + else + { + typeQName = QName.createQName(qnameStr, ((DocumentNavigator) nav).getNamespacePrefixResolver()); + } + // resolve the noderef + NodeRef nodeRef = null; + if (nav.isElement(nodes.get(0))) + { + nodeRef = ((ChildAssociationRef) nodes.get(0)).getChildRef(); + } + else if (nav.isAttribute(nodes.get(0))) + { + nodeRef = ((DocumentNavigator.Property) nodes.get(0)).parent; + } + + DocumentNavigator dNav = (DocumentNavigator) nav; + boolean result = dNav.hasAspect(nodeRef, typeQName); + return result; + } + } + static class Deref implements Function { @@ -643,6 +695,7 @@ public class NodeServiceXPath extends BaseXPath "ends-with", new EndsWithFunction()); registerFunction("", "subtypeOf", new SubTypeOf()); + registerFunction("", "hasAspect", new HasAspect()); registerFunction("", "deref", new Deref()); registerFunction("", "like", new Like()); registerFunction("", "contains", new Contains()); diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java index 77913b864a..47fb1c0086 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java @@ -50,7 +50,7 @@ public abstract class AuthenticationUtil Result doWork() throws Exception; } - private static final String SYSTEM_USER_NAME = "System"; + public static final String SYSTEM_USER_NAME = "System"; private AuthenticationUtil() { diff --git a/source/java/org/alfresco/util/ThreadPoolExecutorFactoryBean.java b/source/java/org/alfresco/util/ThreadPoolExecutorFactoryBean.java index 52bfe12e2b..675fdd436f 100644 --- a/source/java/org/alfresco/util/ThreadPoolExecutorFactoryBean.java +++ b/source/java/org/alfresco/util/ThreadPoolExecutorFactoryBean.java @@ -24,8 +24,9 @@ */ package org.alfresco.util; -import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -35,34 +36,64 @@ import org.springframework.beans.factory.InitializingBean; /** * Factory for {@link java.util.concurrent.ThreadPoolExecutor} instances, - * which cannot easily be constructed using constructor injection. + * which cannot easily be constructed using constructor injection. This instance + * also allows the setting of the thread-specific properties that would otherwise + * require setting a ThreadFactory. *

* This factory provides the a singleton instance of the pool. + *

+ * Defaults are: + *

    + *
  • {@link #setCorePoolSize(int) corePoolSize}: + * 20
  • + *
  • {@link #setMaximumPoolSize(int) maximumPoolSize}: + * Equal to the {@link #setCorePoolSize(int)} at the time of instance creation
  • + *
  • {@link #setKeepAliveTime(int) keepAliveTime}: + * 90 seconds
  • + *
  • {@link #setThreadPriority(int) threadPriority}: + * 1 (LOWEST)
  • + *
  • {@link #setThreadDaemon(boolean) threadDaemon}: + * true
  • + *
  • {@link #setWorkQueue(BlockingQueue) workQueue}: + * An unbounded LinkedBlockingQueue
  • + *
  • {@link #setRejectedExecutionHandler(RejectedExecutionHandler) rejectedExecutionHandler: + * ThreadPoolExecutor.CallerRunsPolicy
  • + *
* * @author Derek Hulley */ public class ThreadPoolExecutorFactoryBean implements FactoryBean, InitializingBean { + private static final int DEFAULT_CORE_POOL_SIZE = 20; + private static final int DEFAULT_MAXIMUM_POOL_SIZE = -1; // -1 is a sign that it must match the core pool size + private static final int DEFAULT_KEEP_ALIVE_TIME = 90; // seconds + private static final int DEFAULT_THREAD_PRIORITY = Thread.MIN_PRIORITY; + private static final boolean DEFAULT_THREAD_DAEMON = Boolean.TRUE; + private static final BlockingQueue DEFAULT_WORK_QUEUE = new LinkedBlockingQueue(); + private static final RejectedExecutionHandler DEFAULT_REJECTED_EXECUTION_HANDLER = new ThreadPoolExecutor.CallerRunsPolicy(); + private int corePoolSize; private int maximumPoolSize; private int keepAliveTime; + private int threadPriority; + private boolean threadDaemon; private BlockingQueue workQueue; + private RejectedExecutionHandler rejectedExecutionHandler; + /** the instance that will be given out by the factory */ private ThreadPoolExecutor instance; /** * Constructor setting default properties: - *
    - *
  • corePoolSize: 5
  • - *
  • maximumPoolSize: 20
  • - *
  • keepAliveTime: 60s
  • - *
  • workQueue: {@link ArrayBlockingQueue}
  • - *
*/ public ThreadPoolExecutorFactoryBean() { - corePoolSize = 5; - maximumPoolSize = 20; - keepAliveTime = 30; + corePoolSize = DEFAULT_CORE_POOL_SIZE; + maximumPoolSize = DEFAULT_MAXIMUM_POOL_SIZE; + keepAliveTime = DEFAULT_KEEP_ALIVE_TIME; + threadPriority = DEFAULT_THREAD_PRIORITY; + threadDaemon = DEFAULT_THREAD_DAEMON; + workQueue = DEFAULT_WORK_QUEUE; + rejectedExecutionHandler = DEFAULT_REJECTED_EXECUTION_HANDLER; } /** @@ -95,6 +126,27 @@ public class ThreadPoolExecutorFactoryBean implements FactoryBean, InitializingB this.keepAliveTime = keepAliveTime; } + /** + * The priority that all threads must have on the scale of 1 to 10, + * where 1 has the lowest priority and 10 has the highest priority. + * + * @param threadPriority the thread priority + */ + public void setThreadPriority(int threadPriority) + { + this.threadPriority = threadPriority; + } + + /** + * Set whether the threads run as daemon threads or not. + * + * @param threadDaemon true to run as daemon + */ + public void setThreadDaemon(boolean threadDaemon) + { + this.threadDaemon = threadDaemon; + } + /** * The optional queue instance to use * @@ -104,15 +156,40 @@ public class ThreadPoolExecutorFactoryBean implements FactoryBean, InitializingB { this.workQueue = workQueue; } + + /** + * The optional handler for when tasks cannot be submitted to the queue. + * The default is the CallerRunsPolicy. + * + * @param rejectedExecutionHandler the handler to use + */ + public void setRejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) + { + this.rejectedExecutionHandler = rejectedExecutionHandler; + } public void afterPropertiesSet() throws Exception { - if (workQueue == null) + // if the maximum pool size has not been set, change it to match the core pool size + if (maximumPoolSize == DEFAULT_MAXIMUM_POOL_SIZE) { - workQueue = new ArrayBlockingQueue(corePoolSize); + maximumPoolSize = corePoolSize; } + + // We need a thread factory + TraceableThreadFactory threadFactory = new TraceableThreadFactory(); + threadFactory.setThreadDaemon(threadDaemon); + threadFactory.setThreadPriority(threadPriority); + // construct the instance - instance = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue); + instance = new ThreadPoolExecutor( + corePoolSize, + maximumPoolSize, + keepAliveTime, + TimeUnit.SECONDS, + workQueue, + threadFactory, + rejectedExecutionHandler); } /** diff --git a/source/java/org/alfresco/util/TraceableThreadFactory.java b/source/java/org/alfresco/util/TraceableThreadFactory.java new file mode 100644 index 0000000000..7c7d466223 --- /dev/null +++ b/source/java/org/alfresco/util/TraceableThreadFactory.java @@ -0,0 +1,101 @@ +/* + * 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.util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A thread factory that spawns threads that are statically visible. Each factory uses a unique + * thread group. All the groups that have been used can be fetched using + * {@link #getActiveThreadGroups()}, allowing iteration of the the threads in the group. + * + * @since 2.1 + * @author Derek Hulley + */ +public class TraceableThreadFactory implements ThreadFactory +{ + private static final AtomicInteger factoryNumber = new AtomicInteger(1); + private static List activeThreadGroups = Collections.synchronizedList(new ArrayList(1)); + + /** + * Get a list of thread groups registered by the factory. + * + * @return Returns a snapshot of thread groups + */ + public static List getActiveThreadGroups() + { + return activeThreadGroups; + } + + private final ThreadGroup group; + private final String namePrefix; + private final AtomicInteger threadNumber; + private boolean threadDaemon; + private int threadPriority; + + + TraceableThreadFactory() + { + this.group = new ThreadGroup("TraceableThreadGroup-" + factoryNumber.getAndIncrement()); + TraceableThreadFactory.activeThreadGroups.add(this.group); + + this.namePrefix = "TraceableThread-" + factoryNumber.getAndIncrement() + "-thread-"; + this.threadNumber = new AtomicInteger(1); + } + + /** + * @param daemon true if all threads created must be daemon threads + */ + public void setThreadDaemon(boolean daemon) + { + this.threadDaemon = daemon; + } + + /** + * + * @param threadPriority the threads priority from 1 (lowest) to 10 (highest) + */ + public void setThreadPriority(int threadPriority) + { + this.threadPriority = threadPriority; + } + + public Thread newThread(Runnable r) + { + Thread thread = new Thread( + group, + r, + namePrefix + threadNumber.getAndIncrement(), + 0); + thread.setDaemon(threadDaemon); + thread.setPriority(threadPriority); + + return thread; + } +}