diff --git a/config/alfresco/avm-console-context.xml b/config/alfresco/avm-console-context.xml index 76887360ee..facf41e22d 100644 --- a/config/alfresco/avm-console-context.xml +++ b/config/alfresco/avm-console-context.xml @@ -11,6 +11,9 @@ config/alfresco/avm-console.properties + + false + diff --git a/config/alfresco/avm-test-context.xml b/config/alfresco/avm-test-context.xml index febaa0501f..7a92555358 100644 --- a/config/alfresco/avm-test-context.xml +++ b/config/alfresco/avm-test-context.xml @@ -12,6 +12,9 @@ config/alfresco/avm-test.properties + + false + --> diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index bbff0f181c..5186d70392 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -64,6 +64,9 @@ true + + false + @@ -109,6 +112,9 @@ 10 + + false + diff --git a/config/alfresco/extension/openoffice-text-context.xml.sample b/config/alfresco/extension/openoffice-text-context.xml.sample new file mode 100644 index 0000000000..36ffa2d92d --- /dev/null +++ b/config/alfresco/extension/openoffice-text-context.xml.sample @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + application/pdf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + application/pdf + + + + + + + + + + + + + + + application/pdf + + + + + + + + + + + + + + + + + + + diff --git a/config/alfresco/extension/pdfminer-transform-context.xml.sample b/config/alfresco/extension/pdfminer-transform-context.xml.sample new file mode 100644 index 0000000000..5907bc8b42 --- /dev/null +++ b/config/alfresco/extension/pdfminer-transform-context.xml.sample @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + application/pdf + + + + + + + + + + + + + + + + application/pdf + + + + + + + + + + + + + + application/pdf + text/plain + + + + + + + + + + + + + + + + + ${python.exe} + ${pdf2txt.py} + + + + + + + 1 + + + + + + + + + + ${python.exe} + ${pdf2txt.py} + -V + -o + ${target} + ${source} + + + + + + 1 + + + + + + + + application/pdf + + + text/plain + + + + + + + diff --git a/config/alfresco/extension/war-deployers-jboss-beans.xml.fragment.sample b/config/alfresco/extension/war-deployers-jboss-beans.xml.fragment.sample new file mode 100644 index 0000000000..3b73824070 --- /dev/null +++ b/config/alfresco/extension/war-deployers-jboss-beans.xml.fragment.sample @@ -0,0 +1,14 @@ + + + + + + + -1 + javax.activation,javax.servlet,javax.servlet.jsp,javax.servlet.jsp.jstl,javax.servlet.jsp.jstl.core,javax.servlet.jsp.jstl.fmt,javax.servlet.jsp.jstl.sql,javax.servlet.jsp.jstl.tlv,javax.xml,javax.xml.bind,javax.xml.bind.annotation,javax.xml.bind.annotation.adapters,javax.xml.bind.attachment,javax.xml.bind.helpers,javax.xml.bind.util,javax.xml.crypto,javax.xml.crypto.dom,javax.xml.crypto.dsig,javax.xml.crypto.dsig.dom,javax.xml.crypto.dsig.keyinfo,javax.xml.crypto.dsig.spec,javax.xml.datatype,javax.xml.messaging,javax.xml.namespace,javax.xml.parsers,javax.xml.rpc,javax.xml.rpc.encoding,javax.xml.rpc.handler,javax.xml.rpc.handler.soap,javax.xml.rpc.holders,javax.xml.rpc.server,javax.xml.rpc.soap,javax.xml.soap,javax.xml.stream,javax.xml.stream.events,javax.xml.stream.util,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.sax,javax.xml.transform.stream,javax.xml.validation,javax.xml.ws,javax.xml.ws.handler,javax.xml.ws.handler.soap,javax.xml.ws.http,javax.xml.ws.soap,javax.xml.ws.spi,javax.xml.ws.wsaddressing,javax.xml.xpath,org.apache.commons.logging,org.apache.commons.logging.impl,org.apache.xerces,org.apache.xerces.dom,org.apache.xerces.dom.events,org.apache.xerces.dom3,org.apache.xerces.dom3.as,org.apache.xerces.impl,org.apache.xerces.impl.dtd,org.apache.xerces.impl.dtd.models,org.apache.xerces.impl.dv,org.apache.xerces.impl.dv.dtd,org.apache.xerces.impl.dv.util,org.apache.xerces.impl.dv.xs,org.apache.xerces.impl.io,org.apache.xerces.impl.msg,org.apache.xerces.impl.validation,org.apache.xerces.impl.xpath,org.apache.xerces.impl.xpath.regex,org.apache.xerces.impl.xs,org.apache.xerces.impl.xs.identity,org.apache.xerces.impl.xs.models,org.apache.xerces.impl.xs.opti,org.apache.xerces.impl.xs.traversers,org.apache.xerces.impl.xs.util,org.apache.xerces.jaxp,org.apache.xerces.jaxp.datatype,org.apache.xerces.jaxp.validation,org.apache.xerces.parsers,org.apache.xerces.util,org.apache.xerces.xinclude,org.apache.xerces.xni,org.apache.xerces.xni.grammars,org.apache.xerces.xni.parser,org.apache.xerces.xpointer,org.apache.xerces.xs,org.apache.xerces.xs.datatypes,org.apache.xml,org.apache.xml.resolver,org.apache.xml.resolver.apps,org.apache.xml.resolver.etc,org.apache.xml.resolver.etc.catalog.dtd,org.apache.xml.resolver.etc.catalog.rng,org.apache.xml.resolver.etc.catalog.xsd,org.apache.xml.resolver.etc.xcatalog.dtd,org.apache.xml.resolver.helpers,org.apache.xml.resolver.readers,org.apache.xml.resolver.tools,org.apache.xml.security,org.apache.xml.security.algorithms,org.apache.xml.security.algorithms.implementations,org.apache.xml.security.c14n,org.apache.xml.security.c14n.helper,org.apache.xml.security.c14n.implementations,org.apache.xml.security.encryption,org.apache.xml.security.exceptions,org.apache.xml.security.keys,org.apache.xml.security.keys.content,org.apache.xml.security.keys.content.keyvalues,org.apache.xml.security.keys.content.x509,org.apache.xml.security.keys.keyresolver,org.apache.xml.security.keys.keyresolver.implementations,org.apache.xml.security.keys.storage,org.apache.xml.security.keys.storage.implementations,org.apache.xml.security.resource,org.apache.xml.security.resource.schema,org.apache.xml.security.signature,org.apache.xml.security.transforms,org.apache.xml.security.transforms.implementations,org.apache.xml.security.transforms.params,org.apache.xml.security.utils,org.apache.xml.security.utils.resolver,org.apache.xml.security.utils.resolver.implementations,org.apache.xml.serialize,org.apache.xmlcommons,org.xml,org.xml.sax,org.xml.sax.ext,org.xml.sax.helpers,org.w3c.css,org.w3c.css.sac,org.w3c.css.sac.helpers,org.w3c.dom,org.w3c.dom.bootstrap,org.w3c.dom.css,org.w3c.dom.events,org.w3c.dom.html,org.w3c.dom.ls,org.w3c.dom.ranges,org.w3c.dom.smil,org.w3c.dom.stylesheets,org.w3c.dom.svg,org.w3c.dom.traversal,org.w3c.dom.views,org.w3c.dom.xpath + + + diff --git a/config/alfresco/extension/xpdf-transform-context.xml.sample b/config/alfresco/extension/xpdf-transform-context.xml.sample new file mode 100644 index 0000000000..9a1459368c --- /dev/null +++ b/config/alfresco/extension/xpdf-transform-context.xml.sample @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + ${pdftotext.root}/pdftotext -enc UTF-8 ${source} ${target} + + + ${pdftotext.root}/pdftotext.exe -enc UTF-8 ${source} ${target} + + + + + + + + + + + + + + + + + chmod 775 ${pdftotext.root}/pdftotext + + + + cmd.exe /C dir + + + + + + + + + + + + + + + application/pdf + + + text/plain + + + + + + + + + + + + transformer.worker.PdfToTextTool + + + + org.alfresco.repo.content.transform.ContentTransformerWorker + + + + + + + + + + + + + + + + + + + + application/pdf + + + + \ No newline at end of file diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml index 14430965e2..27d9410705 100644 --- a/config/alfresco/model/contentModel.xml +++ b/config/alfresco/model/contentModel.xml @@ -910,6 +910,12 @@ d:text + + + d:text + true + false + diff --git a/config/alfresco/remote-email-service-test-context.xml b/config/alfresco/remote-email-service-test-context.xml index 7a01971001..f780f9dd0d 100644 --- a/config/alfresco/remote-email-service-test-context.xml +++ b/config/alfresco/remote-email-service-test-context.xml @@ -13,6 +13,9 @@ classpath:alfresco/remote-email-service-test.properties + + false + diff --git a/config/alfresco/rule-services-context.xml b/config/alfresco/rule-services-context.xml index 8563cd291e..8e3bb6cecd 100644 --- a/config/alfresco/rule-services-context.xml +++ b/config/alfresco/rule-services-context.xml @@ -75,6 +75,8 @@ + + diff --git a/config/test/alfresco/test-context.xml b/config/test/alfresco/test-context.xml index 68e5910710..b2efdbd0e1 100644 --- a/config/test/alfresco/test-context.xml +++ b/config/test/alfresco/test-context.xml @@ -14,6 +14,9 @@ ${db.url}_test + + false + diff --git a/config/test/alfresco/wcm-template-node-test-context.xml b/config/test/alfresco/wcm-template-node-test-context.xml index d115215c07..bc9a5e62c1 100644 --- a/config/test/alfresco/wcm-template-node-test-context.xml +++ b/config/test/alfresco/wcm-template-node-test-context.xml @@ -8,6 +8,9 @@ class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> + + false + diff --git a/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java b/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java index be1839840a..baba3ac0a8 100644 --- a/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java +++ b/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java @@ -695,7 +695,13 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware, } if (direction == CMISRelationshipDirectionEnum.TARGET || direction == CMISRelationshipDirectionEnum.EITHER) { - assocs.addAll(nodeService.getSourceAssocs(node, RegexQNamePattern.MATCH_ALL)); + try + { + assocs.addAll(nodeService.getSourceAssocs(node, RegexQNamePattern.MATCH_ALL)); + } + catch (UnsupportedOperationException uoe) { + // NodeServiceImpl#getSourceAssocs - This operation is not supported for a version store + } } // filter association by type diff --git a/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java index 9a1e375b08..29f1034f18 100644 --- a/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java +++ b/source/java/org/alfresco/filesys/config/ServerConfigurationBean.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,2232 +14,2240 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.filesys.config; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.NetworkInterface; -import java.net.Socket; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.nio.charset.Charset; -import java.nio.charset.IllegalCharsetNameException; -import java.nio.charset.UnsupportedCharsetException; -import java.util.EnumSet; -import java.util.Enumeration; -import java.util.List; -import java.util.StringTokenizer; - -import org.springframework.extensions.config.element.GenericConfigElement; -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.filesys.AbstractServerConfigurationBean; -import org.alfresco.filesys.alfresco.AlfrescoContext; -import org.alfresco.filesys.alfresco.ExtendedDiskInterface; -import org.alfresco.filesys.avm.AVMContext; -import org.alfresco.filesys.avm.AVMDiskDriver; -import org.alfresco.filesys.config.acl.AccessControlListBean; -import org.alfresco.filesys.repo.ContentContext; -import org.alfresco.jlan.ftp.FTPAuthenticator; -import org.alfresco.jlan.ftp.FTPConfigSection; -import org.alfresco.jlan.ftp.FTPPath; -import org.alfresco.jlan.ftp.InvalidPathException; -import org.alfresco.jlan.netbios.NetBIOSSession; -import org.alfresco.jlan.netbios.RFCNetBIOSProtocol; -import org.alfresco.jlan.netbios.win32.Win32NetBIOS; -import org.alfresco.jlan.oncrpc.RpcAuthenticator; -import org.alfresco.jlan.oncrpc.nfs.NFSConfigSection; -import org.alfresco.jlan.server.auth.ICifsAuthenticator; -import org.alfresco.jlan.server.auth.acl.AccessControlList; -import org.alfresco.jlan.server.auth.passthru.DomainMapping; -import org.alfresco.jlan.server.auth.passthru.RangeDomainMapping; -import org.alfresco.jlan.server.auth.passthru.SubnetDomainMapping; -import org.alfresco.jlan.server.config.CoreServerConfigSection; -import org.alfresco.jlan.server.config.InvalidConfigurationException; -import org.alfresco.jlan.server.config.SecurityConfigSection; -import org.alfresco.jlan.server.core.DeviceContext; -import org.alfresco.jlan.server.core.DeviceContextException; -import org.alfresco.jlan.server.core.ShareMapper; -import org.alfresco.jlan.server.core.ShareType; -import org.alfresco.jlan.server.filesys.DiskDeviceContext; -import org.alfresco.jlan.server.filesys.DiskSharedDevice; -import org.alfresco.jlan.server.filesys.FilesystemsConfigSection; -import org.alfresco.jlan.server.filesys.cache.FileStateLockManager; -import org.alfresco.jlan.server.filesys.cache.StandaloneFileStateCache; -import org.alfresco.jlan.server.filesys.cache.hazelcast.ClusterConfigSection; -import org.alfresco.jlan.server.filesys.cache.hazelcast.HazelCastClusterFileStateCache; -import org.alfresco.jlan.server.thread.ThreadRequestPool; -import org.alfresco.jlan.smb.server.CIFSConfigSection; -import org.alfresco.jlan.util.IPAddress; -import org.alfresco.jlan.util.MemorySize; -import org.alfresco.jlan.util.Platform; -import org.alfresco.jlan.util.StringList; -import org.alfresco.jlan.util.X64; -import org.alfresco.repo.management.subsystems.ActivateableBean; - -import com.hazelcast.core.HazelcastInstance; - -/** - * Alfresco File Server Configuration Bean Class - *

- * Acts as an adaptor between JLAN's configuration requirements and the spring configuration of - * the Alfresco filesystem subsystem. - *

- * Also contains an amount of initialisation logic. - * - * @author gkspencer - * @author dward - * @author mrogers - */ -public class ServerConfigurationBean extends AbstractServerConfigurationBean -{ - private CIFSConfigBean cifsConfigBean; - private FTPConfigBean ftpConfigBean; - private NFSConfigBean nfsConfigBean; - private List filesystemContexts; - private boolean avmAllStores; - private SecurityConfigBean securityConfigBean; - private CoreServerConfigBean coreServerConfigBean; + * along with Alfresco. If not, see . + */ +package org.alfresco.filesys.config; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.Socket; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; +import java.util.EnumSet; +import java.util.Enumeration; +import java.util.List; +import java.util.StringTokenizer; + +import org.springframework.extensions.config.element.GenericConfigElement; +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.filesys.AbstractServerConfigurationBean; +import org.alfresco.filesys.alfresco.AlfrescoContext; +import org.alfresco.filesys.alfresco.ExtendedDiskInterface; +import org.alfresco.filesys.avm.AVMContext; +import org.alfresco.filesys.avm.AVMDiskDriver; +import org.alfresco.filesys.config.acl.AccessControlListBean; +import org.alfresco.filesys.repo.ContentContext; +import org.alfresco.jlan.ftp.FTPAuthenticator; +import org.alfresco.jlan.ftp.FTPConfigSection; +import org.alfresco.jlan.ftp.FTPPath; +import org.alfresco.jlan.ftp.InvalidPathException; +import org.alfresco.jlan.netbios.NetBIOSSession; +import org.alfresco.jlan.netbios.RFCNetBIOSProtocol; +import org.alfresco.jlan.netbios.win32.Win32NetBIOS; +import org.alfresco.jlan.oncrpc.RpcAuthenticator; +import org.alfresco.jlan.oncrpc.nfs.NFSConfigSection; +import org.alfresco.jlan.server.auth.ICifsAuthenticator; +import org.alfresco.jlan.server.auth.acl.AccessControlList; +import org.alfresco.jlan.server.auth.passthru.DomainMapping; +import org.alfresco.jlan.server.auth.passthru.RangeDomainMapping; +import org.alfresco.jlan.server.auth.passthru.SubnetDomainMapping; +import org.alfresco.jlan.server.config.CoreServerConfigSection; +import org.alfresco.jlan.server.config.InvalidConfigurationException; +import org.alfresco.jlan.server.config.SecurityConfigSection; +import org.alfresco.jlan.server.core.DeviceContext; +import org.alfresco.jlan.server.core.DeviceContextException; +import org.alfresco.jlan.server.core.ShareMapper; +import org.alfresco.jlan.server.core.ShareType; +import org.alfresco.jlan.server.filesys.DiskDeviceContext; +import org.alfresco.jlan.server.filesys.DiskSharedDevice; +import org.alfresco.jlan.server.filesys.FilesystemsConfigSection; +import org.alfresco.jlan.server.filesys.cache.FileStateLockManager; +import org.alfresco.jlan.server.filesys.cache.StandaloneFileStateCache; +import org.alfresco.jlan.server.filesys.cache.hazelcast.ClusterConfigSection; +import org.alfresco.jlan.server.filesys.cache.hazelcast.HazelCastClusterFileStateCache; +import org.alfresco.jlan.server.thread.ThreadRequestPool; +import org.alfresco.jlan.smb.server.CIFSConfigSection; +import org.alfresco.jlan.util.IPAddress; +import org.alfresco.jlan.util.MemorySize; +import org.alfresco.jlan.util.Platform; +import org.alfresco.jlan.util.StringList; +import org.alfresco.jlan.util.X64; +import org.alfresco.repo.management.subsystems.ActivateableBean; +import org.springframework.beans.factory.DisposableBean; + +import com.hazelcast.core.HazelcastInstance; + +/** + * Alfresco File Server Configuration Bean Class + *

+ * Acts as an adaptor between JLAN's configuration requirements and the spring configuration of + * the Alfresco filesystem subsystem. + *

+ * Also contains an amount of initialisation logic. + * + * @author gkspencer + * @author dward + * @author mrogers + */ +public class ServerConfigurationBean extends AbstractServerConfigurationBean implements DisposableBean +{ + private CIFSConfigBean cifsConfigBean; + private FTPConfigBean ftpConfigBean; + private NFSConfigBean nfsConfigBean; + private List filesystemContexts; + private boolean avmAllStores; + private SecurityConfigBean securityConfigBean; + private CoreServerConfigBean coreServerConfigBean; + + private ThreadRequestPool threadPool; private ClusterConfigBean clusterConfigBean; - - /** - * Default constructor - */ - public ServerConfigurationBean() - { - super(""); - } - - /** - * Class constructor - * - * @param srvName - * String - */ - public ServerConfigurationBean(String srvName) - { - super(srvName); - } - - public void setCifsConfigBean(CIFSConfigBean cifsConfigBean) - { - this.cifsConfigBean = cifsConfigBean; - } - - public void setFtpConfigBean(FTPConfigBean ftpConfigBean) - { - this.ftpConfigBean = ftpConfigBean; - } - - public void setNfsConfigBean(NFSConfigBean nfsConfigBean) - { - this.nfsConfigBean = nfsConfigBean; - } - - public void setFilesystemContexts(List filesystemContexts) - { - this.filesystemContexts = filesystemContexts; - } - - public void setAvmAllStores(boolean avmAllStores) - { - this.avmAllStores = avmAllStores; - } - - public void setSecurityConfigBean(SecurityConfigBean securityConfigBean) - { - this.securityConfigBean = securityConfigBean; - } - - public void setCoreServerConfigBean(CoreServerConfigBean coreServerConfigBean) - { - this.coreServerConfigBean = coreServerConfigBean; - } - - public void setClusterConfigBean(ClusterConfigBean clusterConfigBean) - { - this.clusterConfigBean = clusterConfigBean; - } - - /** - * Process the CIFS server configuration - */ - protected void processCIFSServerConfig() - { - // If the configuration section is not valid then CIFS is disabled - - if (cifsConfigBean == null) - { - removeConfigSection(CIFSConfigSection.SectionName); - return; - } - - // Check if the server has been disabled - if (!cifsConfigBean.getServerEnabled()) - { - removeConfigSection(CIFSConfigSection.SectionName); - return; - } - - // Before we go any further, let's make sure there's a compatible authenticator in the authentication chain. - ICifsAuthenticator authenticator = cifsConfigBean.getAuthenticator(); - if (authenticator == null || authenticator instanceof ActivateableBean && !((ActivateableBean)authenticator).isActive()) - { - logger.warn("No enabled CIFS authenticator found in authentication chain. CIFS Server disabled"); - removeConfigSection(CIFSConfigSection.SectionName); - return; - } - - // Create the CIFS server configuration section - - CIFSConfigSection cifsConfig = new CIFSConfigSection(this); - - try - { - // Check if native code calls should be disabled on Windows - if (cifsConfigBean.getDisableNativeCode()) - { - // Disable native code calls so that the JNI DLL is not required - - cifsConfig.setNativeCodeDisabled(true); - m_disableNativeCode = true; - - // Warning - - logger.warn("CIFS server native calls disabled, JNI code will not be used"); - } - - // Get the network broadcast address - // - // Note: We need to set this first as the call to getLocalDomainName() may use a NetBIOS - // name lookup, so the broadcast mask must be set before then. - - String broadcastAddess = cifsConfigBean.getBroadcastAddress(); - if (broadcastAddess != null && broadcastAddess.length() > 0) - { - - // Check if the broadcast mask is a valid numeric IP address - - if (IPAddress.isNumericAddress(broadcastAddess) == false) - throw new AlfrescoRuntimeException("Invalid broadcast mask, must be n.n.n.n format"); - - // Set the network broadcast mask - - cifsConfig.setBroadcastMask(broadcastAddess); - } - - // Get the host configuration - - String hostName = cifsConfigBean.getServerName(); - if (hostName == null || hostName.length() == 0) - throw new AlfrescoRuntimeException("Host name not specified or invalid"); - - // Check if the host name contains the local name token - - int pos = hostName.indexOf(TokenLocalName); - if (pos != -1) - { - - // Get the local server name - - String srvName = getLocalServerName(true); - - // Rebuild the host name substituting the token with the local server name - - StringBuilder hostStr = new StringBuilder(); - - hostStr.append(hostName.substring(0, pos)); - hostStr.append(srvName); - - pos += TokenLocalName.length(); - if (pos < hostName.length()) - hostStr.append(hostName.substring(pos)); - - hostName = hostStr.toString(); - - // Make sure the CIFS server name does not match the local server name - - if (hostName.equals(srvName) && getPlatformType() == Platform.Type.WINDOWS) - throw new AlfrescoRuntimeException("CIFS server name must be unique"); - } - - // Check if the host name is longer than 15 characters. NetBIOS only allows a maximum of 16 characters in - // the - // server name with the last character reserved for the service type. - - if (hostName.length() > 15) - { - // Truncate the CIFS server name - - hostName = hostName.substring(0, 15); - - // Output a warning - - logger.warn("CIFS server name is longer than 15 characters, truncated to " + hostName); - } - - // Set the CIFS server name - - cifsConfig.setServerName(hostName.toUpperCase()); - setServerName(hostName.toUpperCase()); - - // Get the domain/workgroup name - - String domain = cifsConfigBean.getDomainName(); - if (domain != null && domain.length() > 0) - { - // Set the domain/workgroup name - - cifsConfig.setDomainName(domain.toUpperCase()); - } - else - { - // Get the local domain/workgroup name - - String localDomain = getLocalDomainName(); - - if (localDomain == null && (getPlatformType() != Platform.Type.WINDOWS || isNativeCodeDisabled())) - { - // Use a default domain/workgroup name - - localDomain = "WORKGROUP"; - - // Output a warning - - logger.error("Failed to get local domain/workgroup name, using default of " + localDomain); - logger.error("(This may be due to firewall settings or incorrect setting)"); - } - - // Set the local domain/workgroup that the CIFS server belongs to - - cifsConfig.setDomainName(localDomain); - } - - // Check for a server comment - String comment = cifsConfigBean.getServerComment(); - if (comment != null && comment.length() > 0) - { - cifsConfig.setComment(comment); - } - - // Check for a bind address - - // Check if the network adapter name has been specified - String bindToAdapter = cifsConfigBean.getBindToAdapter(); - String bindTo; - - if (bindToAdapter != null && bindToAdapter.length() > 0) - { - - // Get the IP address for the adapter - - InetAddress bindAddr = parseAdapterName(bindToAdapter); - - // Set the bind address for the server - - cifsConfig.setSMBBindAddress(bindAddr); - } - else if ((bindTo = cifsConfigBean.getBindToAddress()) != null && bindTo.length() > 0 - && !bindTo.equals(BIND_TO_IGNORE)) - { - - // Validate the bind address - try - { - // Check the bind address - - InetAddress bindAddr = InetAddress.getByName(bindTo); - - // Set the bind address for the server - - cifsConfig.setSMBBindAddress(bindAddr); - } - catch (UnknownHostException ex) - { - throw new AlfrescoRuntimeException("Invalid CIFS server bind address"); - } - } - - // Get the authenticator - - if (authenticator != null) - { - cifsConfig.setAuthenticator(authenticator); - } - else - throw new AlfrescoRuntimeException("CIFS authenticator not specified"); - - // Check if the host announcer has been disabled - - if (!cifsConfigBean.getHostAccouncerEnabled()) - { - // Switch off the host announcer - - cifsConfig.setHostAnnouncer( false); - - // Log that host announcements are not enabled - - logger.info("Host announcements not enabled"); - } - else - { - // Check for an announcement interval - - Integer interval = cifsConfigBean.getHostAccounceInterval(); - if (interval != null) - { - cifsConfig.setHostAnnounceInterval(interval); - } - - // Check if the domain name has been set, this is required if the - // host announcer is enabled - - if (cifsConfig.getDomainName() == null) - throw new AlfrescoRuntimeException("Domain name must be specified if host announcement is enabled"); - - // Enable host announcement - - cifsConfig.setHostAnnouncer(true); - } - - // Check if NetBIOS SMB is enabled - NetBIOSSMBConfigBean netBIOSSMBConfigBean = cifsConfigBean.getNetBIOSSMB(); - if (netBIOSSMBConfigBean != null) - { - // Check if NetBIOS over TCP/IP is enabled for the current platform - - String platformsStr = netBIOSSMBConfigBean.getPlatforms(); - boolean platformOK = false; - - if (platformsStr != null && platformsStr.length() > 0) - { - // Parse the list of platforms that NetBIOS over TCP/IP is to be enabled for and - // check if the current platform is included - - EnumSet enabledPlatforms = parsePlatformString(platformsStr); - if (enabledPlatforms.contains(getPlatformType())) - platformOK = true; - } - else - { - // No restriction on platforms - - platformOK = true; - } - - // Enable the NetBIOS SMB support, if enabled for this platform - - cifsConfig.setNetBIOSSMB(platformOK); - - // Parse/check NetBIOS settings, if enabled - - if (cifsConfig.hasNetBIOSSMB()) - { - // Check if the broadcast mask has been specified - - if (cifsConfig.getBroadcastMask() == null) - throw new AlfrescoRuntimeException("Network broadcast mask not specified"); - - // Check for a bind address - - String bindto = netBIOSSMBConfigBean.getBindTo(); - if (bindto != null && bindto.length() > 0 && !bindto.equals(BIND_TO_IGNORE)) - { - - // Validate the bind address - - try - { - - // Check the bind address - - InetAddress bindAddr = InetAddress.getByName(bindto); - - // Set the bind address for the NetBIOS name server - - cifsConfig.setNetBIOSBindAddress(bindAddr); - } - catch (UnknownHostException ex) - { - throw new AlfrescoRuntimeException("Invalid NetBIOS bind address"); - } - } - else if (cifsConfig.hasSMBBindAddress()) - { - - // Use the SMB bind address for the NetBIOS name server - - cifsConfig.setNetBIOSBindAddress(cifsConfig.getSMBBindAddress()); - } - else - { - // Get a list of all the local addresses - - InetAddress[] addrs = null; - - try - { - // Get the local server IP address list - - addrs = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName()); - } - catch (UnknownHostException ex) - { - logger.error("Failed to get local address list", ex); - } - - // Check the address list for one or more valid local addresses filtering out the loopback - // address - - int addrCnt = 0; - - if (addrs != null) - { - for (int i = 0; i < addrs.length; i++) - { - - // Check for a valid address, filter out '127.0.0.1' and '0.0.0.0' addresses - - if (addrs[i].getHostAddress().equals("127.0.0.1") == false - && addrs[i].getHostAddress().equals("0.0.0.0") == false) - addrCnt++; - } - } - - // Check if any addresses were found - - if (addrCnt == 0) - { - // Enumerate the network adapter list - - Enumeration niEnum = null; - - try - { - niEnum = NetworkInterface.getNetworkInterfaces(); - } - catch (SocketException ex) - { - } - - if (niEnum != null) - { - while (niEnum.hasMoreElements()) - { - // Get the current network interface - - NetworkInterface ni = niEnum.nextElement(); - - // Enumerate the addresses for the network adapter - - Enumeration niAddrs = ni.getInetAddresses(); - if (niAddrs != null) - { - // Check for any valid addresses - - while (niAddrs.hasMoreElements()) - { - InetAddress curAddr = niAddrs.nextElement(); - - if (curAddr.getHostAddress().equals("127.0.0.1") == false - && curAddr.getHostAddress().equals("0.0.0.0") == false) - addrCnt++; - } - } - } - - // DEBUG - - if (addrCnt > 0 && logger.isDebugEnabled()) - logger.debug("Found valid IP address from interface list"); - } - - // Check if we found any valid network addresses - - if (addrCnt == 0) - { - // Log the available IP addresses - - if (logger.isDebugEnabled()) - { - logger.debug("Local address list dump :-"); - if (addrs != null) - { - for (int i = 0; i < addrs.length; i++) - logger.debug(" Address: " + addrs[i]); - } - else - logger.debug(" No addresses"); - } - - // Throw an exception to stop the CIFS/NetBIOS name server from starting - - throw new AlfrescoRuntimeException( - "Failed to get IP address(es) for the local server, check hosts file and/or DNS setup"); - } - } - } - - // Check if the session port has been specified - - Integer portNum = netBIOSSMBConfigBean.getSessionPort(); - if (portNum != null) - { - cifsConfig.setSessionPort(portNum); - if (cifsConfig.getSessionPort() <= 0 || cifsConfig.getSessionPort() >= 65535) - throw new AlfrescoRuntimeException("NetBIOS session port out of valid range"); - } - - // Check if the name port has been specified - - portNum = netBIOSSMBConfigBean.getNamePort(); - if (portNum != null) - { - cifsConfig.setNameServerPort(portNum); - if (cifsConfig.getNameServerPort() <= 0 || cifsConfig.getNameServerPort() >= 65535) - throw new AlfrescoRuntimeException("NetBIOS name port out of valid range"); - } - - // Check if the datagram port has been specified - - portNum = netBIOSSMBConfigBean.getDatagramPort(); - if (portNum != null) - { - cifsConfig.setDatagramPort(portNum); - if (cifsConfig.getDatagramPort() <= 0 || cifsConfig.getDatagramPort() >= 65535) - throw new AlfrescoRuntimeException("NetBIOS datagram port out of valid range"); - } - - // Check for a bind address - - String attr = netBIOSSMBConfigBean.getBindTo(); - if (attr != null && attr.length() > 0 && !attr.equals(BIND_TO_IGNORE)) - { - - // Validate the bind address - - try - { - - // Check the bind address - - InetAddress bindAddr = InetAddress.getByName(attr); - - // Set the bind address for the NetBIOS name server - - cifsConfig.setNetBIOSBindAddress(bindAddr); - } - catch (UnknownHostException ex) - { - throw new InvalidConfigurationException(ex.toString()); - } - } - - // Check for a bind address using the adapter name - - else if ((attr = netBIOSSMBConfigBean.getAdapter()) != null && attr.length() > 0) - { - - // Get the bind address via the network adapter name - - InetAddress bindAddr = parseAdapterName(attr); - cifsConfig.setNetBIOSBindAddress(bindAddr); - } - else if (cifsConfig.hasSMBBindAddress()) - { - - // Use the SMB bind address for the NetBIOS name server - - cifsConfig.setNetBIOSBindAddress(cifsConfig.getSMBBindAddress()); - } - - } - } - else - { - - // Disable NetBIOS SMB support - - cifsConfig.setNetBIOSSMB(false); - } - - // Check if TCP/IP SMB is enabled - - TcpipSMBConfigBean tcpipSMBConfigBean = cifsConfigBean.getTcpipSMB(); - if (tcpipSMBConfigBean != null) - { - - // Check if native SMB is enabled for the current platform - - String platformsStr = tcpipSMBConfigBean.getPlatforms(); - boolean platformOK = false; - - if (platformsStr != null) - { - // Parse the list of platforms that native SMB is to be enabled for and - // check if the current platform is included - - EnumSet enabledPlatforms = parsePlatformString(platformsStr); - if (enabledPlatforms.contains(getPlatformType())) - platformOK = true; - } - else - { - // No restriction on platforms - - platformOK = true; - } - - // Enable the TCP/IP SMB support, if enabled for this platform - - cifsConfig.setTcpipSMB(platformOK); - - // Check if the port has been specified - - Integer portNum = tcpipSMBConfigBean.getPort(); - if (portNum != null) - { - cifsConfig.setTcpipSMBPort(portNum); - if (cifsConfig.getTcpipSMBPort() <= 0 || cifsConfig.getTcpipSMBPort() >= 65535) - throw new AlfrescoRuntimeException("TCP/IP SMB port out of valid range"); - } - - // Check if IPv6 support should be enabled - - if ( tcpipSMBConfigBean.getIpv6Enabled()) - { - try - { - // Use the IPv6 bind all address - - cifsConfig.setSMBBindAddress( InetAddress.getByName( "::")); - - // DEBUG - - if ( logger.isInfoEnabled()) - logger.info("Enabled CIFS IPv6 bind address for native SMB"); - } - catch ( UnknownHostException ex) - { - throw new AlfrescoRuntimeException("Failed to enable IPv6 bind address, " + ex.getMessage()); - } - } - - } - else - { - - // Disable TCP/IP SMB support - - cifsConfig.setTcpipSMB(false); - } - - // Check if Win32 NetBIOS is enabled - - Win32NetBIOSConfigBean win32NetBIOSConfigBean = cifsConfigBean.getWin32NetBIOS(); - if (win32NetBIOSConfigBean != null) - { - - // Check if the Win32 NetBIOS server name has been specified - - String win32Name = win32NetBIOSConfigBean.getName(); - if (win32Name != null && win32Name.length() > 0) - { - - // Validate the name - - if (win32Name.length() > 16) - throw new AlfrescoRuntimeException("Invalid Win32 NetBIOS name, " + win32Name); - - // Set the Win32 NetBIOS file server name - - cifsConfig.setWin32NetBIOSName(win32Name); - } - - // Check if the Win32 NetBIOS LANA has been specified - - String lanaStr = win32NetBIOSConfigBean.getLana(); - if (lanaStr != null && lanaStr.length() > 0) - { - // Check if the LANA has been specified as an IP address or adapter name - - int lana = -1; - - if (IPAddress.isNumericAddress(lanaStr)) - { - - // Convert the IP address to a LANA id - - lana = Win32NetBIOS.getLANAForIPAddress(lanaStr); - if (lana == -1) - throw new AlfrescoRuntimeException("Failed to convert IP address " + lanaStr + " to a LANA"); - } - else if (lanaStr.length() > 1 && Character.isLetter(lanaStr.charAt(0))) - { - - // Convert the network adapter to a LANA id - - lana = Win32NetBIOS.getLANAForAdapterName(lanaStr); - if (lana == -1) - throw new AlfrescoRuntimeException("Failed to convert network adapter " + lanaStr - + " to a LANA"); - } - else - { - - try - { - lana = Integer.parseInt(lanaStr); - } - catch (NumberFormatException ex) - { - throw new AlfrescoRuntimeException("Invalid win32 NetBIOS LANA specified"); - } - } - - // LANA should be in the range 0-255 - - if (lana < 0 || lana > 255) - throw new AlfrescoRuntimeException("Invalid Win32 NetBIOS LANA number, " + lana); - - // Set the LANA number - - cifsConfig.setWin32LANA(lana); - } - - // Check if the native NetBIOS interface has been specified, either 'winsock' or 'netbios' - - String nativeAPI = win32NetBIOSConfigBean.getApi(); - if (nativeAPI != null && nativeAPI.length() > 0) - { - // Validate the API type - - boolean useWinsock = true; - - if (nativeAPI.equalsIgnoreCase("netbios")) - useWinsock = false; - else if (nativeAPI.equalsIgnoreCase("winsock") == false) - throw new AlfrescoRuntimeException("Invalid NetBIOS API type, spefify 'winsock' or 'netbios'"); - - // Set the NetBIOS API to use - - cifsConfig.setWin32WinsockNetBIOS(useWinsock); - } - - // Force the older NetBIOS API code to be used on 64Bit Windows - - if (cifsConfig.useWinsockNetBIOS() == true && X64.isWindows64()) - { - // Debug - - if (logger.isDebugEnabled()) - logger.debug("Using older Netbios() API code"); - - // Use the older NetBIOS API code - - cifsConfig.setWin32WinsockNetBIOS(false); - } - - // Check if the current operating system is supported by the Win32 - // NetBIOS handler - - String osName = System.getProperty("os.name"); - if (osName.startsWith("Windows") - && (osName.endsWith("95") == false && osName.endsWith("98") == false && osName.endsWith("ME") == false) - && isNativeCodeDisabled() == false) - { - - // Call the Win32NetBIOS native code to make sure it is initialized - - if (Win32NetBIOS.LanaEnumerate() != null) - { - // Enable Win32 NetBIOS - - cifsConfig.setWin32NetBIOS(true); - } - else - { - logger.warn("No NetBIOS LANAs available"); - } - } - else - { - - // Win32 NetBIOS not supported on the current operating system - - cifsConfig.setWin32NetBIOS(false); - } - } - else - { - - // Disable Win32 NetBIOS - - cifsConfig.setWin32NetBIOS(false); - } - - // Check if the Win32 host announcer has been disabled - - if ( !cifsConfigBean.getWin32HostAnnouncerEnabled()) - { - // Switch off the Win32 host announcer - - cifsConfig.setWin32HostAnnouncer( false); - - // Log that host announcements are not enabled - - logger.info("Win32 host announcements not enabled"); - } - else - { - // Check for an announcement interval - Integer interval = cifsConfigBean.getWin32HostAnnounceInterval(); - if (interval != null) - { - cifsConfig.setWin32HostAnnounceInterval(interval); - } - - // Check if the domain name has been set, this is required if the - // host announcer is enabled - - if (cifsConfig.getDomainName() == null) - throw new AlfrescoRuntimeException("Domain name must be specified if host announcement is enabled"); - - // Enable Win32 NetBIOS host announcement - - cifsConfig.setWin32HostAnnouncer(true); - } - - // Check if NetBIOS and/or TCP/IP SMB have been enabled - - if (cifsConfig.hasNetBIOSSMB() == false && cifsConfig.hasTcpipSMB() == false - && cifsConfig.hasWin32NetBIOS() == false) - throw new AlfrescoRuntimeException("NetBIOS SMB, TCP/IP SMB or Win32 NetBIOS must be enabled"); - - // Check if WINS servers are configured - - WINSConfigBean winsConfigBean = cifsConfigBean.getWINSConfig(); - - if (winsConfigBean != null && !winsConfigBean.isAutoDetectEnabled()) - { - - // Get the primary WINS server - - String priWins = winsConfigBean.getPrimary(); - - if (priWins == null || priWins.length() == 0) - throw new AlfrescoRuntimeException("No primary WINS server configured"); - - // Validate the WINS server address - - InetAddress primaryWINS = null; - - try - { - primaryWINS = InetAddress.getByName(priWins); - } - catch (UnknownHostException ex) - { - throw new AlfrescoRuntimeException("Invalid primary WINS server address, " + priWins); - } - - // Check if a secondary WINS server has been specified - - String secWins = winsConfigBean.getSecondary(); - InetAddress secondaryWINS = null; - - if (secWins != null && secWins.length() > 0) - { - - // Validate the secondary WINS server address - - try - { - secondaryWINS = InetAddress.getByName(secWins); - } - catch (UnknownHostException ex) - { - throw new AlfrescoRuntimeException("Invalid secondary WINS server address, " + secWins); - } - } - - // Set the WINS server address(es) - - cifsConfig.setPrimaryWINSServer(primaryWINS); - if (secondaryWINS != null) - cifsConfig.setSecondaryWINSServer(secondaryWINS); - - // Pass the setting to the NetBIOS session class - - NetBIOSSession.setDefaultWINSServer(primaryWINS); - } - - // Check if WINS is configured, if we are running on Windows and socket based NetBIOS is enabled - - else if (cifsConfig.hasNetBIOSSMB() && getPlatformType() == Platform.Type.WINDOWS && !isNativeCodeDisabled()) - { - // Get the WINS server list - - String winsServers = Win32NetBIOS.getWINSServerList(); - - if (winsServers != null) - { - // Use the first WINS server address for now - - StringTokenizer tokens = new StringTokenizer(winsServers, ","); - String addr = tokens.nextToken(); - - try - { - // Convert to a network address and check if the WINS server is accessible - - InetAddress winsAddr = InetAddress.getByName(addr); - - Socket winsSocket = new Socket(); - InetSocketAddress sockAddr = new InetSocketAddress(winsAddr, RFCNetBIOSProtocol.NAME_PORT); - - winsSocket.connect(sockAddr, 3000); - winsSocket.close(); - - // Set the primary WINS server address - - cifsConfig.setPrimaryWINSServer(winsAddr); - - // Debug - - if (logger.isDebugEnabled()) - logger.debug("Configuring to use WINS server " + addr); - } - catch (UnknownHostException ex) - { - throw new AlfrescoRuntimeException("Invalid auto WINS server address, " + addr); - } - catch (IOException ex) - { - if (logger.isDebugEnabled()) - logger.debug("Failed to connect to auto WINS server " + addr); - } - } - } - - // Check for session debug flags - - String flags = cifsConfigBean.getSessionDebugFlags(); - - int sessDbg = 0; - - if (flags != null && flags.length() > 0) - { - - // Parse the flags - - flags = flags.toUpperCase(); - StringTokenizer token = new StringTokenizer(flags, ","); - - while (token.hasMoreTokens()) - { - // Get the current debug flag token - - String dbg = token.nextToken().trim(); - - // Find the debug flag name - - int idx = 0; - - while (idx < m_sessDbgStr.length && m_sessDbgStr[idx].equalsIgnoreCase(dbg) == false) - idx++; - - if (idx > m_sessDbgStr.length) - throw new AlfrescoRuntimeException("Invalid session debug flag, " + dbg); - - // Set the debug flag - - sessDbg += 1 << idx; - } - } - - // Set the session debug flags - - cifsConfig.setSessionDebugFlags(sessDbg); - - // Check if NIO based socket code should be disabled - - if (cifsConfigBean.getDisableNIO()) - { - - // Disable NIO based code - - cifsConfig.setDisableNIOCode(true); - - // DEBUG - - if (logger.isDebugEnabled()) - logger.debug("NIO based code disabled for CIFS server"); - } - - - // Check if a session timeout is configured - - Integer tmo = cifsConfigBean.getSessionTimeout(); - if (tmo != null) - { - - // Validate the session timeout value - - if (tmo < 0 || tmo > MaxSessionTimeout) - throw new AlfrescoRuntimeException("Session timeout out of range (0 - " + MaxSessionTimeout + ")"); - - // Convert the session timeout to milliseconds - - cifsConfig.setSocketTimeout(tmo * 1000); - } - } - catch (InvalidConfigurationException ex) - { - throw new AlfrescoRuntimeException(ex.getMessage()); - } - } - - /** - * Process the FTP server configuration - */ - protected void processFTPServerConfig() - { - // If the configuration section is not valid then FTP is disabled - - if (ftpConfigBean == null) - { - removeConfigSection(FTPConfigSection.SectionName); - return; - } - - // Check if the server has been disabled - - if (!ftpConfigBean.getServerEnabled()) - { - removeConfigSection(FTPConfigSection.SectionName); - return; - } - - // Create the FTP configuration section - - FTPConfigSection ftpConfig = new FTPConfigSection(this); - - try - { - // Check for a bind address - - String bindText = ftpConfigBean.getBindTo(); - if (bindText != null && bindText.length() > 0 && !bindText.equals(BIND_TO_IGNORE)) - { - - // Validate the bind address - - try - { - - // Check the bind address - - InetAddress bindAddr = InetAddress.getByName(bindText); - - // Set the bind address for the FTP server - - ftpConfig.setFTPBindAddress(bindAddr); - } - catch (UnknownHostException ex) - { - throw new AlfrescoRuntimeException("Invalid FTP bindto address, " + bindText); - } - } - - // Check for an FTP server port - - Integer port = ftpConfigBean.getPort(); - if (port != null) - { - ftpConfig.setFTPPort(port); - if (ftpConfig.getFTPPort() <= 0 || ftpConfig.getFTPPort() >= 65535) - throw new AlfrescoRuntimeException("FTP server port out of valid range"); - } - else - { - - // Use the default FTP port - - ftpConfig.setFTPPort(DefaultFTPServerPort); - } - - // Check if anonymous login is allowed - - if (ftpConfigBean.getAllowAnonymous()) - { - - // Enable anonymous login to the FTP server - - ftpConfig.setAllowAnonymousFTP(true); - - // Check if an anonymous account has been specified - - String anonAcc = ftpConfigBean.getAnonymousAccount(); - if (anonAcc != null && anonAcc.length() > 0) - { - - // Set the anonymous account name - - ftpConfig.setAnonymousFTPAccount(anonAcc); - - // Check if the anonymous account name is valid - - if (ftpConfig.getAnonymousFTPAccount() == null || ftpConfig.getAnonymousFTPAccount().length() == 0) - throw new AlfrescoRuntimeException("Anonymous FTP account invalid"); - } - else - { - - // Use the default anonymous account name - - ftpConfig.setAnonymousFTPAccount(DefaultFTPAnonymousAccount); - } - } - else - { - - // Disable anonymous logins - - ftpConfig.setAllowAnonymousFTP(false); - } - - // Check if a root path has been specified - - String rootPath = ftpConfigBean.getRootDirectory(); - if (rootPath != null && rootPath.length() > 0) - { - try - { - - // Parse the path - - new FTPPath(rootPath); - - // Set the root path - - ftpConfig.setFTPRootPath(rootPath); - } - catch (InvalidPathException ex) - { - throw new AlfrescoRuntimeException("Invalid FTP root directory, " + rootPath); - } - } - - // Check for FTP debug flags - - String flags = ftpConfigBean.getDebugFlags(); - int ftpDbg = 0; - - if (flags != null) - { - - // Parse the flags - - flags = flags.toUpperCase(); - StringTokenizer token = new StringTokenizer(flags, ","); - - while (token.hasMoreTokens()) - { - - // Get the current debug flag token - - String dbg = token.nextToken().trim(); - - // Find the debug flag name - - int idx = 0; - - while (idx < m_ftpDebugStr.length && m_ftpDebugStr[idx].equalsIgnoreCase(dbg) == false) - idx++; - - if (idx >= m_ftpDebugStr.length) - throw new AlfrescoRuntimeException("Invalid FTP debug flag, " + dbg); - - // Set the debug flag - - ftpDbg += 1 << idx; - } - - // Set the FTP debug flags - - ftpConfig.setFTPDebug(ftpDbg); - } - - // Check if a character set has been specified - - String charSet = ftpConfigBean.getCharSet(); - if (charSet != null && charSet.length() > 0) - { - - try - { - - // Validate the character set name - - Charset.forName(charSet); - - // Set the FTP character set - - ftpConfig.setFTPCharacterSet(charSet); - } - catch (IllegalCharsetNameException ex) - { - throw new AlfrescoRuntimeException("Illegal character set name, " + charSet); - } - catch (UnsupportedCharsetException ex) - { - throw new AlfrescoRuntimeException("Unsupported character set name, " + charSet); - } - } - - // Check if an authenticator has been specified - - FTPAuthenticator auth = ftpConfigBean.getAuthenticator(); - if (auth != null) - { - - // Initialize and set the authenticator class - - ftpConfig.setAuthenticator(auth); - } - else - throw new AlfrescoRuntimeException("FTP authenticator not specified"); - - // Check if a data port range has been specified - - if ( ftpConfigBean.getDataPortFrom() != 0 && ftpConfigBean.getDataPortTo() != 0) { - - // Range check the data port values - - int rangeFrom = ftpConfigBean.getDataPortFrom(); - int rangeTo = ftpConfigBean.getDataPortTo(); - - if ( rangeFrom != 0 && rangeTo != 0) { - - // Validate the FTP data port range - - if ( rangeFrom < 1024 || rangeFrom > 65535) - throw new InvalidConfigurationException("Invalid FTP data port range from value, " + rangeFrom); - - if ( rangeTo < 1024 || rangeTo > 65535) - throw new InvalidConfigurationException("Invalid FTP data port range to value, " + rangeTo); - - if ( rangeFrom >= rangeTo) - throw new InvalidConfigurationException("Invalid FTP data port range, " + rangeFrom + "-" + rangeTo); - - // Set the FTP data port range - - ftpConfig.setFTPDataPortLow(rangeFrom); - ftpConfig.setFTPDataPortHigh(rangeTo); - - // Log the data port range - - logger.info("FTP server data ports restricted to range " + rangeFrom + ":" + rangeTo); - } - } - - // FTPS parameter parsing - // - // Check if a key store path has been specified - - if ( ftpConfigBean.getKeyStorePath() != null && ftpConfigBean.getKeyStorePath().length() > 0) { - - // Get the path to the key store, check that the file exists - - String keyStorePath = ftpConfigBean.getKeyStorePath(); - File keyStoreFile = new File( keyStorePath); - - if ( keyStoreFile.exists() == false) - throw new InvalidConfigurationException("FTPS key store file does not exist, " + keyStorePath); - else if ( keyStoreFile.isDirectory()) - throw new InvalidConfigurationException("FTPS key store path is a directory, " + keyStorePath); - - // Set the key store path - - ftpConfig.setKeyStorePath( keyStorePath); - } - - // Check if the trust store path has been specified - - if ( ftpConfigBean.getTrustStorePath() != null && ftpConfigBean.getTrustStorePath().length() > 0) { - - // Get the path to the trust store, check that the file exists - - String trustStorePath = ftpConfigBean.getTrustStorePath(); - File trustStoreFile = new File( trustStorePath); - - if ( trustStoreFile.exists() == false) - throw new InvalidConfigurationException("FTPS trust store file does not exist, " + trustStorePath); - else if ( trustStoreFile.isDirectory()) - throw new InvalidConfigurationException("FTPS trust store path is a directory, " + trustStorePath); - - // Set the trust store path - - ftpConfig.setTrustStorePath( trustStorePath); - } - - // Check if the store passphrase has been specified - - if ( ftpConfigBean.getPassphrase() != null && ftpConfigBean.getPassphrase().length() > 0) { - - // Set the store passphrase - - ftpConfig.setPassphrase( ftpConfigBean.getPassphrase()); - } - - // Check if only secure sessions should be allowed to logon - - if ( ftpConfigBean.hasRequireSecureSession()) { - - // Only allow secure sessions to logon to the FTP server - - ftpConfig.setRequireSecureSession( true); - } - - // Check that all the required FTPS parameters have been set - - if ( ftpConfig.getKeyStorePath() != null || ftpConfig.getTrustStorePath() != null || ftpConfig.getPassphrase() != null) { - - // Make sure all parameters are set - - if ( ftpConfig.getKeyStorePath() == null || ftpConfig.getTrustStorePath() == null || ftpConfig.getPassphrase() == null) - throw new InvalidConfigurationException("FTPS configuration requires keyStore, trustStore and storePassphrase to be set"); - } - - // Check if SSLEngine debug output should be enabled - - if ( ftpConfigBean.hasSslEngineDebug()) { - - // Enable SSLEngine debug output - - System.setProperty("javax.net.debug", "ssl,handshake"); - } - } - catch (InvalidConfigurationException ex) - { - throw new AlfrescoRuntimeException(ex.getMessage()); - } - } - - /** - * Process the NFS server configuration - */ - protected void processNFSServerConfig() - { - // If the configuration section is not valid then NFS is disabled - - if (nfsConfigBean == null) - { - removeConfigSection(NFSConfigSection.SectionName); - return; - } - - // Check if the server has been disabled - - if (!nfsConfigBean.getServerEnabled()) - { - removeConfigSection(NFSConfigSection.SectionName); - return; - } - - // Create the NFS configuration section - - NFSConfigSection nfsConfig = new NFSConfigSection(this); - - try - { - // Check if the port mapper is enabled - - if (nfsConfigBean.getPortMapperEnabled()) - nfsConfig.setNFSPortMapper(true); - - // Check for the thread pool size - - Integer poolSize = nfsConfigBean.getThreadPool(); - - if (poolSize != null) - { - - // Range check the pool size value - - if (poolSize < 4) - throw new AlfrescoRuntimeException("NFS thread pool size is below minimum of 4"); - - // Set the thread pool size - - nfsConfig.setNFSThreadPoolSize(poolSize); - } - - // NFS packet pool size - - Integer pktPoolSize = nfsConfigBean.getPacketPool(); - - if (pktPoolSize != null) - { - // Range check the pool size value - - if (pktPoolSize < 10) - throw new AlfrescoRuntimeException("NFS packet pool size is below minimum of 10"); - - if (pktPoolSize < nfsConfig.getNFSThreadPoolSize() + 1) - throw new AlfrescoRuntimeException("NFS packet pool must be at least thread pool size plus one"); - - // Set the packet pool size - - nfsConfig.setNFSPacketPoolSize(pktPoolSize); - } - - // Check for a port mapper server port - - Integer portMapperPort = nfsConfigBean.getPortMapperPort(); - if (portMapperPort != null) - { - nfsConfig.setPortMapperPort(portMapperPort); - if ( nfsConfig.getPortMapperPort() == -1) { - logger.info("NFS portmapper registration disabled"); - } - else { - if (nfsConfig.getPortMapperPort() <= 0 || nfsConfig.getPortMapperPort() >= 65535) - throw new AlfrescoRuntimeException("Port mapper server port out of valid range"); - } - } - - // Check for a mount server port - - Integer mountServerPort = nfsConfigBean.getMountServerPort(); - if (mountServerPort != null) - { - nfsConfig.setMountServerPort(mountServerPort); - if (nfsConfig.getMountServerPort() < 0 || nfsConfig.getMountServerPort() >= 65535) - throw new AlfrescoRuntimeException("Mount server port out of valid range"); - } - - // Check for an NFS server port - - Integer nfsServerPort = nfsConfigBean.getNfsServerPort(); - if (nfsServerPort != null) - { - nfsConfig.setNFSServerPort(nfsServerPort); - if (nfsConfig.getNFSServerPort() < 0 || nfsConfig.getNFSServerPort() >= 65535) - throw new AlfrescoRuntimeException("NFS server port out of valid range"); - } - - // Check for an RPC registration port - - Integer rpcRegisterPort = nfsConfigBean.getRpcRegisterPort(); - if ( rpcRegisterPort != null) - { - nfsConfig.setRPCRegistrationPort( rpcRegisterPort); - if ( nfsConfig.getRPCRegistrationPort() < 0 || nfsConfig.getRPCRegistrationPort() >= 65535) - throw new AlfrescoRuntimeException("RPC registrtion port out of valid range"); - } - - // Check for NFS debug flags - - String flags = nfsConfigBean.getDebugFlags(); - int nfsDbg = 0; - - if (flags != null && flags.length() > 0) - { - - // Parse the flags - - flags = flags.toUpperCase(); - StringTokenizer token = new StringTokenizer(flags, ","); - - while (token.hasMoreTokens()) - { - - // Get the current debug flag token - - String dbg = token.nextToken().trim(); - - // Find the debug flag name - - int idx = 0; - - while (idx < m_nfsDebugStr.length && m_nfsDebugStr[idx].equalsIgnoreCase(dbg) == false) - idx++; - - if (idx >= m_nfsDebugStr.length) - throw new AlfrescoRuntimeException("Invalid NFS debug flag, " + dbg); - - // Set the debug flag - - nfsDbg += 1 << idx; - } - - // Set the NFS debug flags - - nfsConfig.setNFSDebug(nfsDbg); - } - - // Check if mount server debug output is enabled - - if (nfsConfigBean.getMountServerDebug()) - nfsConfig.setMountServerDebug(true); - - // Check if portmapper debug output is enabled - - if (nfsConfigBean.getPortMapperDebug()) - nfsConfig.setPortMapperDebug(true); - - // Create the RPC authenticator - RpcAuthenticator rpcAuthenticator = nfsConfigBean.getRpcAuthenticator(); - if (rpcAuthenticator != null) - { - nfsConfig.setRpcAuthenticator(rpcAuthenticator); - } - else - throw new AlfrescoRuntimeException("RPC authenticator configuration missing, require user mappings"); - } - catch (InvalidConfigurationException ex) - { - throw new AlfrescoRuntimeException(ex.getMessage()); - } - } - - /** - * Process the filesystems configuration - */ - protected void processFilesystemsConfig() - { - // Create the filesystems configuration section - - FilesystemsConfigSection fsysConfig = new FilesystemsConfigSection(this); - - // Access the security configuration section - - SecurityConfigSection secConfig = (SecurityConfigSection) getConfigSection(SecurityConfigSection.SectionName); - - // Process the filesystems list - - if (this.filesystemContexts != null) - { - - // Add the filesystems - - for (DeviceContext filesystem : this.filesystemContexts) - { - - // Get the current filesystem configuration - - try - { - // Check the filesystem type and use the appropriate driver - - DiskSharedDevice filesys = null; - - if (filesystem instanceof AVMContext) - { - // Create a new filesystem driver instance and register a context for - // the new filesystem - - ExtendedDiskInterface filesysDriver = getAvmDiskInterface(); - DiskDeviceContext diskCtx = (DiskDeviceContext) filesystem; - - if(clusterConfigBean != null && clusterConfigBean.getClusterEnabled()) - { - if(logger.isDebugEnabled()) - { - logger.debug("start hazelcast cache : " + clusterConfigBean.getClusterName() + ", shareName: "+ diskCtx.getShareName()); - } - GenericConfigElement hazelConfig = createClusterConfig(diskCtx.getShareName()); - HazelCastClusterFileStateCache hazel = new HazelCastClusterFileStateCache(); - hazel.initializeCache(hazelConfig, this); - diskCtx.setStateCache(hazel); - } - else - { - // Check if the filesystem uses the file state cache, if so then add to the file state reaper - StandaloneFileStateCache standaloneCache = new StandaloneFileStateCache(); - standaloneCache.initializeCache( new GenericConfigElement( ""), this); - diskCtx.setStateCache(standaloneCache); - } - if ( diskCtx.hasStateCache()) { - - // Register the state cache with the reaper thread - - fsysConfig.addFileStateCache( filesystem.getDeviceName(), diskCtx.getStateCache()); - } - - filesysDriver.registerContext(filesystem); - - // Create the shared filesystem - - filesys = new DiskSharedDevice(filesystem.getDeviceName(), filesysDriver, (AVMContext)filesystem); - filesys.setConfiguration( this); - // Start the filesystem - - ((AVMContext)filesystem).startFilesystem(filesys); - } - else - { - // Create a new filesystem driver instance and register a context for - // the new filesystem - - ExtendedDiskInterface filesysDriver = getRepoDiskInterface(); - ContentContext filesysContext = (ContentContext) filesystem; - - if(clusterConfigBean != null && clusterConfigBean.getClusterEnabled()) - { - if(logger.isDebugEnabled()) - { - logger.debug("start hazelcast cache : " + clusterConfigBean.getClusterName() + ", shareName: "+ filesysContext.getShareName()); - } - GenericConfigElement hazelConfig = createClusterConfig(filesysContext.getShareName()); - HazelCastClusterFileStateCache hazel = new HazelCastClusterFileStateCache(); - hazel.initializeCache(hazelConfig, this); - filesysContext.setStateCache(hazel); - } - else - { - // Create state cache here and inject - StandaloneFileStateCache standaloneCache = new StandaloneFileStateCache(); - standaloneCache.initializeCache( new GenericConfigElement( ""), this); - filesysContext.setStateCache(standaloneCache); - } - - if ( filesysContext.hasStateCache()) { - - // Register the state cache with the reaper thread - - fsysConfig.addFileStateCache( filesystem.getDeviceName(), filesysContext.getStateCache()); - - // Create the lock manager for the context. - FileStateLockManager lockMgr = new FileStateLockManager(filesysContext.getStateCache()); - filesysContext.setLockManager(lockMgr); - filesysContext.setOpLockManager(lockMgr); - } - - filesysDriver.registerContext(filesystem); - - // Check if an access control list has been specified - - AccessControlList acls = null; - AccessControlListBean accessControls = filesysContext.getAccessControlList(); - if (accessControls != null) - { - // Parse the access control list - acls = accessControls.toAccessControlList(secConfig); - } - else if (secConfig.hasGlobalAccessControls()) - { - - // Use the global access control list for this disk share - acls = secConfig.getGlobalAccessControls(); - } - - // Create the shared filesystem - - filesys = new DiskSharedDevice(filesystem.getDeviceName(), filesysDriver, filesysContext); - filesys.setConfiguration( this); - - // Add any access controls to the share - - filesys.setAccessControlList(acls); - - - - // Check if change notifications should be enabled - - if ( filesysContext.getDisableChangeNotifications() == false) - filesysContext.enableChangeHandler( true); - - // Start the filesystem - - filesysContext.startFilesystem(filesys); - } - - // Add the new filesystem - - fsysConfig.addShare(filesys); - } - catch (DeviceContextException ex) - { - throw new AlfrescoRuntimeException("Error creating filesystem " + filesystem.getDeviceName(), ex); - } - catch (InvalidConfigurationException ex) - { - throw new AlfrescoRuntimeException(ex.getMessage(), ex); - } - } - } - else - { - // No filesystems defined - - logger.warn("No filesystems defined"); - } - - // Check if shares should be added for all AVM stores - if (this.avmAllStores && getAvmDiskInterface() != null) - { - // Get the list of store names - - AVMDiskDriver avmDriver = (AVMDiskDriver) getAvmDiskInterface(); - StringList storeNames = avmDriver.getAVMStoreNames(); - - // Add shares for each of the store names, if the share name does not already exist - - if (storeNames != null && storeNames.numberOfStrings() > 0) - { - // Add a share for each store - - for (int i = 0; i < storeNames.numberOfStrings(); i++) - { - String storeName = storeNames.getStringAt(i); - - // Check if a share of the same name already exists - - if (fsysConfig.getShares().findShare(storeName, ShareType.DISK, true) == null) - { - // Create the new share for the store - - AVMContext avmContext = new AVMContext(storeName, storeName + ":/", AVMContext.VERSION_HEAD); -// avmContext.enableStateCache(this, true); - - // Create the shared filesystem - - DiskSharedDevice filesys = new DiskSharedDevice(storeName, avmDriver, avmContext); - filesys.setConfiguration( this); - - fsysConfig.addShare( filesys); - - // DEBUG - - if (logger.isDebugEnabled()) - logger.debug("Added AVM share " + storeName); - } - } - } - } - - - // home folder share mapper could be declared in security config - } - - /** - * Process the security configuration - */ - protected void processSecurityConfig() - { - // Create the security configuration section - - SecurityConfigSection secConfig = new SecurityConfigSection(this); - - try - { - // Check if global access controls have been specified - - AccessControlListBean accessControls = securityConfigBean.getGlobalAccessControl(); - - if (accessControls != null) - { - // Parse the access control list - AccessControlList acls = accessControls.toAccessControlList(secConfig); - if (acls != null) - secConfig.setGlobalAccessControls(acls); - } - - - // Check if a JCE provider class has been specified - - String jceProvider = securityConfigBean.getJCEProvider(); - if (jceProvider != null && jceProvider.length() > 0) - { - - // Set the JCE provider - - secConfig.setJCEProvider(jceProvider); - } - else - { - // Use the default Bouncy Castle JCE provider - - secConfig.setJCEProvider("org.bouncycastle.jce.provider.BouncyCastleProvider"); - } - - // Check if a share mapper has been specified - - ShareMapper shareMapper = securityConfigBean.getShareMapper(); - if (shareMapper != null) - { - // Associate the share mapper - secConfig.setShareMapper(shareMapper); - } - else - { - // Check if the tenant service is enabled - if (m_tenantService != null && m_tenantService.isEnabled()) - { - // Initialize the multi-tenancy share mapper - - secConfig.setShareMapper("org.alfresco.filesys.alfresco.MultiTenantShareMapper", - new GenericConfigElement("shareMapper")); - - } - } - - // Check if any domain mappings have been specified - - List mappings = securityConfigBean.getDomainMappings(); - if (mappings != null) - { - DomainMapping mapping = null; - - for (DomainMappingConfigBean domainMap : mappings) - { - // Get the domain name - - String name = domainMap.getName(); - - // Check if the domain is specified by subnet or range - - String subnetStr = domainMap.getSubnet(); - String rangeFromStr; - if (subnetStr != null && subnetStr.length() > 0) - { - String maskStr = domainMap.getMask(); - - // Parse the subnet and mask, to validate and convert to int values - - int subnet = IPAddress.parseNumericAddress(subnetStr); - int mask = IPAddress.parseNumericAddress(maskStr); - - if (subnet == 0 || mask == 0) - throw new AlfrescoRuntimeException("Invalid subnet/mask for domain mapping " + name); - - // Create the subnet domain mapping - - mapping = new SubnetDomainMapping(name, subnet, mask); - } - else if ((rangeFromStr = domainMap.getRangeFrom()) != null && rangeFromStr.length() > 0) - { - String rangeToStr = domainMap.getRangeTo(); - - // Parse the range from/to values and convert to int values - - int rangeFrom = IPAddress.parseNumericAddress(rangeFromStr); - int rangeTo = IPAddress.parseNumericAddress(rangeToStr); - - if (rangeFrom == 0 || rangeTo == 0) - throw new AlfrescoRuntimeException("Invalid address range domain mapping " + name); - - // Create the subnet domain mapping - - mapping = new RangeDomainMapping(name, rangeFrom, rangeTo); - } - else - throw new AlfrescoRuntimeException("Invalid domain mapping specified"); - - // Add the domain mapping - - secConfig.addDomainMapping(mapping); - } - } - } - catch (InvalidConfigurationException ex) - { - throw new AlfrescoRuntimeException(ex.getMessage()); - } - } - - /** - * Process the core server configuration - * - * @exception InvalidConfigurationException - */ - protected void processCoreServerConfig() throws InvalidConfigurationException - { - // Create the core server configuration section - - CoreServerConfigSection coreConfig = new CoreServerConfigSection(this); - - // Check if the CIFS server is not enabled, do not create the thread/memory pools - - if ( cifsConfigBean == null || cifsConfigBean.getServerEnabled() == false) - return; - - // Check if the server core element has been specified - - if (coreServerConfigBean == null) - { - - // Configure a default memory pool - - coreConfig.setMemoryPool(DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc); - - // Configure a default thread pool size - - coreConfig.setThreadPool(DefaultThreadPoolInit, DefaultThreadPoolMax); - return; - } - - // Check if the thread pool size has been specified - - Integer initSize = coreServerConfigBean.getThreadPoolInit(); - if (initSize == null) - { - initSize = DefaultThreadPoolInit; - } - Integer maxSize = coreServerConfigBean.getThreadPoolMax(); - if (maxSize == null) - { - maxSize = DefaultThreadPoolMax; - } - - // Range check the thread pool size - - if (initSize < ThreadRequestPool.MinimumWorkerThreads) - throw new InvalidConfigurationException("Thread pool size below minimum allowed size"); - - if (initSize > ThreadRequestPool.MaximumWorkerThreads) - throw new InvalidConfigurationException("Thread pool size above maximum allowed size"); - - // Range check the maximum thread pool size - - if (maxSize < ThreadRequestPool.MinimumWorkerThreads) - throw new InvalidConfigurationException("Thread pool maximum size below minimum allowed size"); - - if (maxSize > ThreadRequestPool.MaximumWorkerThreads) - throw new InvalidConfigurationException("Thread pool maximum size above maximum allowed size"); - - if (maxSize < initSize) - throw new InvalidConfigurationException("Initial size is larger than maxmimum size"); - - // Configure the thread pool - - coreConfig.setThreadPool(initSize, maxSize); - - // Check if thread pool debug output is enabled - - if (coreServerConfigBean.getThreadPoolDebug()) - coreConfig.getThreadPool().setDebug(true); - - // Check if the packet sizes/allocations have been specified - - List packetSizes = coreServerConfigBean.getMemoryPacketSizes(); - if (packetSizes != null) - { - - // Calculate the array size for the packet size/allocation arrays - - int elemCnt = packetSizes.size(); - - // Create the packet size, initial allocation and maximum allocation arrays - - int[] pktSizes = new int[elemCnt]; - int[] initSizes = new int[elemCnt]; - int[] maxSizes = new int[elemCnt]; - - int elemIdx = 0; - - // Process the packet size elements - for (MemoryPacketConfigBean curChild : packetSizes) - { - - // Get the packet size - - int pktSize = -1; - - Long pktSizeLong = curChild.getSize(); - if (pktSizeLong == null) - throw new InvalidConfigurationException("Memory pool packet size not specified"); - - // Parse the packet size - - try - { - pktSize = MemorySize.getByteValueInt(pktSizeLong.toString()); - } - catch (NumberFormatException ex) - { - throw new InvalidConfigurationException("Memory pool packet size, invalid size value, " - + pktSizeLong); - } - - // Make sure the packet sizes have been specified in ascending order - - if (elemIdx > 0 && pktSizes[elemIdx - 1] >= pktSize) - throw new InvalidConfigurationException( - "Invalid packet size specified, less than/equal to previous packet size"); - - // Get the initial allocation for the current packet size - Integer initAlloc = curChild.getInit(); - if (initAlloc == null) - throw new InvalidConfigurationException("Memory pool initial allocation not specified"); - - // Range check the initial allocation - - if (initAlloc < MemoryPoolMinimumAllocation) - throw new InvalidConfigurationException("Initial memory pool allocation below minimum of " - + MemoryPoolMinimumAllocation); - - if (initAlloc > MemoryPoolMaximumAllocation) - throw new InvalidConfigurationException("Initial memory pool allocation above maximum of " - + MemoryPoolMaximumAllocation); - - // Get the maximum allocation for the current packet size - - Integer maxAlloc = curChild.getMax(); - if (maxAlloc == null) - throw new InvalidConfigurationException("Memory pool maximum allocation not specified"); - - // Range check the maximum allocation - - if (maxAlloc < MemoryPoolMinimumAllocation) - throw new InvalidConfigurationException("Maximum memory pool allocation below minimum of " - + MemoryPoolMinimumAllocation); - - if (initAlloc > MemoryPoolMaximumAllocation) - throw new InvalidConfigurationException("Maximum memory pool allocation above maximum of " - + MemoryPoolMaximumAllocation); - - // Set the current packet size elements - - pktSizes[elemIdx] = pktSize; - initSizes[elemIdx] = initAlloc; - maxSizes[elemIdx] = maxAlloc; - - elemIdx++; - } - - // Check if all elements were used in the packet size/allocation arrays - - if (elemIdx < pktSizes.length) - { - - // Re-allocate the packet size/allocation arrays - - int[] newPktSizes = new int[elemIdx]; - int[] newInitSizes = new int[elemIdx]; - int[] newMaxSizes = new int[elemIdx]; - - // Copy the values to the shorter arrays - - System.arraycopy(pktSizes, 0, newPktSizes, 0, elemIdx); - System.arraycopy(initSizes, 0, newInitSizes, 0, elemIdx); - System.arraycopy(maxSizes, 0, newMaxSizes, 0, elemIdx); - - // Move the new arrays into place - - pktSizes = newPktSizes; - initSizes = newInitSizes; - maxSizes = newMaxSizes; - } - - // Configure the memory pool - - coreConfig.setMemoryPool(pktSizes, initSizes, maxSizes); - } - else - { - - // Configure a default memory pool - - coreConfig.setMemoryPool(DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc); - } - } - - /** - * Initialise a runtime context - not configured through spring e.g MT. - * - * TODO - what about desktop actions etc? - * - * @param diskCtx - */ - public void initialiseRuntimeContext(AlfrescoContext diskCtx) - { - if (diskCtx.getStateCache() == null) { - - // Set the state cache, use a hard coded standalone cache for now - FilesystemsConfigSection filesysConfig = (FilesystemsConfigSection) this.getConfigSection( FilesystemsConfigSection.SectionName); - - if ( filesysConfig != null) - { - - try - { - if(clusterConfigBean != null && clusterConfigBean.getClusterEnabled()) - { - if(logger.isDebugEnabled()) - { - logger.debug("start hazelcast cache : " + clusterConfigBean.getClusterName() + ", shareName: "+ diskCtx.getShareName()); - } - GenericConfigElement hazelConfig = createClusterConfig(diskCtx.getShareName()); - HazelCastClusterFileStateCache hazel = new HazelCastClusterFileStateCache(); - hazel.initializeCache(hazelConfig, this); - diskCtx.setStateCache(hazel); - } - else - { - // Create a standalone state cache - StandaloneFileStateCache standaloneCache = new StandaloneFileStateCache(); - standaloneCache.initializeCache( new GenericConfigElement( ""), this); - filesysConfig.addFileStateCache( diskCtx.getDeviceName(), standaloneCache); - diskCtx.setStateCache( standaloneCache); - } - - FileStateLockManager lockMgr = new FileStateLockManager(diskCtx.getStateCache()); - diskCtx.setLockManager(lockMgr); - diskCtx.setOpLockManager(lockMgr); - } - catch ( InvalidConfigurationException ex) - { - throw new AlfrescoRuntimeException( "Failed to initialize standalone state cache for " + diskCtx.getDeviceName()); - } - } - } - } - - - @Override - protected void processClusterConfig() throws InvalidConfigurationException - { - -// Done by org.alfresco.jlan.server.config.ServerConfiguration.closeConfiguration -// /** -// * Close the old hazelcast configuration -// */ -// ClusterConfigSection secConfig = (ClusterConfigSection) getConfigSection(ClusterConfigSection.SectionName); -// { -// if(secConfig != null) -// { -// secConfig.closeConfig(); -// } -// } - - if (clusterConfigBean == null || !clusterConfigBean.getClusterEnabled()) - { - removeConfigSection(ClusterConfigSection.SectionName); - logger.info("Filesystem cluster cache not enabled"); - return; - } - - String clusterName = clusterConfigBean.getClusterName(); - if (clusterName == null || clusterName.length() == 0) - { - throw new InvalidConfigurationException("Cluster name not specified or invalid"); - } - - String clusterFile = clusterConfigBean.getConfigFile(); - if (clusterFile == null || clusterFile.length() == 0) - { - throw new InvalidConfigurationException("Cluster config file not specified or invalid"); - } - - // New Hazelcast instance created here within the ClusterConfigSection + + /** + * Default constructor + */ + public ServerConfigurationBean() + { + super(""); + } + + /** + * Class constructor + * + * @param srvName + * String + */ + public ServerConfigurationBean(String srvName) + { + super(srvName); + } + + public void setCifsConfigBean(CIFSConfigBean cifsConfigBean) + { + this.cifsConfigBean = cifsConfigBean; + } + + public void setFtpConfigBean(FTPConfigBean ftpConfigBean) + { + this.ftpConfigBean = ftpConfigBean; + } + + public void setNfsConfigBean(NFSConfigBean nfsConfigBean) + { + this.nfsConfigBean = nfsConfigBean; + } + + public void setFilesystemContexts(List filesystemContexts) + { + this.filesystemContexts = filesystemContexts; + } + + public void setAvmAllStores(boolean avmAllStores) + { + this.avmAllStores = avmAllStores; + } + + public void setSecurityConfigBean(SecurityConfigBean securityConfigBean) + { + this.securityConfigBean = securityConfigBean; + } + + public void setCoreServerConfigBean(CoreServerConfigBean coreServerConfigBean) + { + this.coreServerConfigBean = coreServerConfigBean; + } + + public void setClusterConfigBean(ClusterConfigBean clusterConfigBean) + { + this.clusterConfigBean = clusterConfigBean; + } + + /** + * Process the CIFS server configuration + */ + protected void processCIFSServerConfig() + { + // If the configuration section is not valid then CIFS is disabled + + if (cifsConfigBean == null) + { + removeConfigSection(CIFSConfigSection.SectionName); + return; + } + + // Check if the server has been disabled + if (!cifsConfigBean.getServerEnabled()) + { + removeConfigSection(CIFSConfigSection.SectionName); + return; + } + + // Before we go any further, let's make sure there's a compatible authenticator in the authentication chain. + ICifsAuthenticator authenticator = cifsConfigBean.getAuthenticator(); + if (authenticator == null || authenticator instanceof ActivateableBean && !((ActivateableBean)authenticator).isActive()) + { + logger.warn("No enabled CIFS authenticator found in authentication chain. CIFS Server disabled"); + removeConfigSection(CIFSConfigSection.SectionName); + return; + } + + // Create the CIFS server configuration section + + CIFSConfigSection cifsConfig = new CIFSConfigSection(this); + + try + { + // Check if native code calls should be disabled on Windows + if (cifsConfigBean.getDisableNativeCode()) + { + // Disable native code calls so that the JNI DLL is not required + + cifsConfig.setNativeCodeDisabled(true); + m_disableNativeCode = true; + + // Warning + + logger.warn("CIFS server native calls disabled, JNI code will not be used"); + } + + // Get the network broadcast address + // + // Note: We need to set this first as the call to getLocalDomainName() may use a NetBIOS + // name lookup, so the broadcast mask must be set before then. + + String broadcastAddess = cifsConfigBean.getBroadcastAddress(); + if (broadcastAddess != null && broadcastAddess.length() > 0) + { + + // Check if the broadcast mask is a valid numeric IP address + + if (IPAddress.isNumericAddress(broadcastAddess) == false) + throw new AlfrescoRuntimeException("Invalid broadcast mask, must be n.n.n.n format"); + + // Set the network broadcast mask + + cifsConfig.setBroadcastMask(broadcastAddess); + } + + // Get the host configuration + + String hostName = cifsConfigBean.getServerName(); + if (hostName == null || hostName.length() == 0) + throw new AlfrescoRuntimeException("Host name not specified or invalid"); + + // Check if the host name contains the local name token + + int pos = hostName.indexOf(TokenLocalName); + if (pos != -1) + { + + // Get the local server name + + String srvName = getLocalServerName(true); + + // Rebuild the host name substituting the token with the local server name + + StringBuilder hostStr = new StringBuilder(); + + hostStr.append(hostName.substring(0, pos)); + hostStr.append(srvName); + + pos += TokenLocalName.length(); + if (pos < hostName.length()) + hostStr.append(hostName.substring(pos)); + + hostName = hostStr.toString(); + + // Make sure the CIFS server name does not match the local server name + + if (hostName.equals(srvName) && getPlatformType() == Platform.Type.WINDOWS) + throw new AlfrescoRuntimeException("CIFS server name must be unique"); + } + + // Check if the host name is longer than 15 characters. NetBIOS only allows a maximum of 16 characters in + // the + // server name with the last character reserved for the service type. + + if (hostName.length() > 15) + { + // Truncate the CIFS server name + + hostName = hostName.substring(0, 15); + + // Output a warning + + logger.warn("CIFS server name is longer than 15 characters, truncated to " + hostName); + } + + // Set the CIFS server name + + cifsConfig.setServerName(hostName.toUpperCase()); + setServerName(hostName.toUpperCase()); + + // Get the domain/workgroup name + + String domain = cifsConfigBean.getDomainName(); + if (domain != null && domain.length() > 0) + { + // Set the domain/workgroup name + + cifsConfig.setDomainName(domain.toUpperCase()); + } + else + { + // Get the local domain/workgroup name + + String localDomain = getLocalDomainName(); + + if (localDomain == null && (getPlatformType() != Platform.Type.WINDOWS || isNativeCodeDisabled())) + { + // Use a default domain/workgroup name + + localDomain = "WORKGROUP"; + + // Output a warning + + logger.error("Failed to get local domain/workgroup name, using default of " + localDomain); + logger.error("(This may be due to firewall settings or incorrect setting)"); + } + + // Set the local domain/workgroup that the CIFS server belongs to + + cifsConfig.setDomainName(localDomain); + } + + // Check for a server comment + String comment = cifsConfigBean.getServerComment(); + if (comment != null && comment.length() > 0) + { + cifsConfig.setComment(comment); + } + + // Check for a bind address + + // Check if the network adapter name has been specified + String bindToAdapter = cifsConfigBean.getBindToAdapter(); + String bindTo; + + if (bindToAdapter != null && bindToAdapter.length() > 0) + { + + // Get the IP address for the adapter + + InetAddress bindAddr = parseAdapterName(bindToAdapter); + + // Set the bind address for the server + + cifsConfig.setSMBBindAddress(bindAddr); + } + else if ((bindTo = cifsConfigBean.getBindToAddress()) != null && bindTo.length() > 0 + && !bindTo.equals(BIND_TO_IGNORE)) + { + + // Validate the bind address + try + { + // Check the bind address + + InetAddress bindAddr = InetAddress.getByName(bindTo); + + // Set the bind address for the server + + cifsConfig.setSMBBindAddress(bindAddr); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid CIFS server bind address"); + } + } + + // Get the authenticator + + if (authenticator != null) + { + cifsConfig.setAuthenticator(authenticator); + } + else + throw new AlfrescoRuntimeException("CIFS authenticator not specified"); + + // Check if the host announcer has been disabled + + if (!cifsConfigBean.getHostAccouncerEnabled()) + { + // Switch off the host announcer + + cifsConfig.setHostAnnouncer( false); + + // Log that host announcements are not enabled + + logger.info("Host announcements not enabled"); + } + else + { + // Check for an announcement interval + + Integer interval = cifsConfigBean.getHostAccounceInterval(); + if (interval != null) + { + cifsConfig.setHostAnnounceInterval(interval); + } + + // Check if the domain name has been set, this is required if the + // host announcer is enabled + + if (cifsConfig.getDomainName() == null) + throw new AlfrescoRuntimeException("Domain name must be specified if host announcement is enabled"); + + // Enable host announcement + + cifsConfig.setHostAnnouncer(true); + } + + // Check if NetBIOS SMB is enabled + NetBIOSSMBConfigBean netBIOSSMBConfigBean = cifsConfigBean.getNetBIOSSMB(); + if (netBIOSSMBConfigBean != null) + { + // Check if NetBIOS over TCP/IP is enabled for the current platform + + String platformsStr = netBIOSSMBConfigBean.getPlatforms(); + boolean platformOK = false; + + if (platformsStr != null && platformsStr.length() > 0) + { + // Parse the list of platforms that NetBIOS over TCP/IP is to be enabled for and + // check if the current platform is included + + EnumSet enabledPlatforms = parsePlatformString(platformsStr); + if (enabledPlatforms.contains(getPlatformType())) + platformOK = true; + } + else + { + // No restriction on platforms + + platformOK = true; + } + + // Enable the NetBIOS SMB support, if enabled for this platform + + cifsConfig.setNetBIOSSMB(platformOK); + + // Parse/check NetBIOS settings, if enabled + + if (cifsConfig.hasNetBIOSSMB()) + { + // Check if the broadcast mask has been specified + + if (cifsConfig.getBroadcastMask() == null) + throw new AlfrescoRuntimeException("Network broadcast mask not specified"); + + // Check for a bind address + + String bindto = netBIOSSMBConfigBean.getBindTo(); + if (bindto != null && bindto.length() > 0 && !bindto.equals(BIND_TO_IGNORE)) + { + + // Validate the bind address + + try + { + + // Check the bind address + + InetAddress bindAddr = InetAddress.getByName(bindto); + + // Set the bind address for the NetBIOS name server + + cifsConfig.setNetBIOSBindAddress(bindAddr); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid NetBIOS bind address"); + } + } + else if (cifsConfig.hasSMBBindAddress()) + { + + // Use the SMB bind address for the NetBIOS name server + + cifsConfig.setNetBIOSBindAddress(cifsConfig.getSMBBindAddress()); + } + else + { + // Get a list of all the local addresses + + InetAddress[] addrs = null; + + try + { + // Get the local server IP address list + + addrs = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName()); + } + catch (UnknownHostException ex) + { + logger.error("Failed to get local address list", ex); + } + + // Check the address list for one or more valid local addresses filtering out the loopback + // address + + int addrCnt = 0; + + if (addrs != null) + { + for (int i = 0; i < addrs.length; i++) + { + + // Check for a valid address, filter out '127.0.0.1' and '0.0.0.0' addresses + + if (addrs[i].getHostAddress().equals("127.0.0.1") == false + && addrs[i].getHostAddress().equals("0.0.0.0") == false) + addrCnt++; + } + } + + // Check if any addresses were found + + if (addrCnt == 0) + { + // Enumerate the network adapter list + + Enumeration niEnum = null; + + try + { + niEnum = NetworkInterface.getNetworkInterfaces(); + } + catch (SocketException ex) + { + } + + if (niEnum != null) + { + while (niEnum.hasMoreElements()) + { + // Get the current network interface + + NetworkInterface ni = niEnum.nextElement(); + + // Enumerate the addresses for the network adapter + + Enumeration niAddrs = ni.getInetAddresses(); + if (niAddrs != null) + { + // Check for any valid addresses + + while (niAddrs.hasMoreElements()) + { + InetAddress curAddr = niAddrs.nextElement(); + + if (curAddr.getHostAddress().equals("127.0.0.1") == false + && curAddr.getHostAddress().equals("0.0.0.0") == false) + addrCnt++; + } + } + } + + // DEBUG + + if (addrCnt > 0 && logger.isDebugEnabled()) + logger.debug("Found valid IP address from interface list"); + } + + // Check if we found any valid network addresses + + if (addrCnt == 0) + { + // Log the available IP addresses + + if (logger.isDebugEnabled()) + { + logger.debug("Local address list dump :-"); + if (addrs != null) + { + for (int i = 0; i < addrs.length; i++) + logger.debug(" Address: " + addrs[i]); + } + else + logger.debug(" No addresses"); + } + + // Throw an exception to stop the CIFS/NetBIOS name server from starting + + throw new AlfrescoRuntimeException( + "Failed to get IP address(es) for the local server, check hosts file and/or DNS setup"); + } + } + } + + // Check if the session port has been specified + + Integer portNum = netBIOSSMBConfigBean.getSessionPort(); + if (portNum != null) + { + cifsConfig.setSessionPort(portNum); + if (cifsConfig.getSessionPort() <= 0 || cifsConfig.getSessionPort() >= 65535) + throw new AlfrescoRuntimeException("NetBIOS session port out of valid range"); + } + + // Check if the name port has been specified + + portNum = netBIOSSMBConfigBean.getNamePort(); + if (portNum != null) + { + cifsConfig.setNameServerPort(portNum); + if (cifsConfig.getNameServerPort() <= 0 || cifsConfig.getNameServerPort() >= 65535) + throw new AlfrescoRuntimeException("NetBIOS name port out of valid range"); + } + + // Check if the datagram port has been specified + + portNum = netBIOSSMBConfigBean.getDatagramPort(); + if (portNum != null) + { + cifsConfig.setDatagramPort(portNum); + if (cifsConfig.getDatagramPort() <= 0 || cifsConfig.getDatagramPort() >= 65535) + throw new AlfrescoRuntimeException("NetBIOS datagram port out of valid range"); + } + + // Check for a bind address + + String attr = netBIOSSMBConfigBean.getBindTo(); + if (attr != null && attr.length() > 0 && !attr.equals(BIND_TO_IGNORE)) + { + + // Validate the bind address + + try + { + + // Check the bind address + + InetAddress bindAddr = InetAddress.getByName(attr); + + // Set the bind address for the NetBIOS name server + + cifsConfig.setNetBIOSBindAddress(bindAddr); + } + catch (UnknownHostException ex) + { + throw new InvalidConfigurationException(ex.toString()); + } + } + + // Check for a bind address using the adapter name + + else if ((attr = netBIOSSMBConfigBean.getAdapter()) != null && attr.length() > 0) + { + + // Get the bind address via the network adapter name + + InetAddress bindAddr = parseAdapterName(attr); + cifsConfig.setNetBIOSBindAddress(bindAddr); + } + else if (cifsConfig.hasSMBBindAddress()) + { + + // Use the SMB bind address for the NetBIOS name server + + cifsConfig.setNetBIOSBindAddress(cifsConfig.getSMBBindAddress()); + } + + } + } + else + { + + // Disable NetBIOS SMB support + + cifsConfig.setNetBIOSSMB(false); + } + + // Check if TCP/IP SMB is enabled + + TcpipSMBConfigBean tcpipSMBConfigBean = cifsConfigBean.getTcpipSMB(); + if (tcpipSMBConfigBean != null) + { + + // Check if native SMB is enabled for the current platform + + String platformsStr = tcpipSMBConfigBean.getPlatforms(); + boolean platformOK = false; + + if (platformsStr != null) + { + // Parse the list of platforms that native SMB is to be enabled for and + // check if the current platform is included + + EnumSet enabledPlatforms = parsePlatformString(platformsStr); + if (enabledPlatforms.contains(getPlatformType())) + platformOK = true; + } + else + { + // No restriction on platforms + + platformOK = true; + } + + // Enable the TCP/IP SMB support, if enabled for this platform + + cifsConfig.setTcpipSMB(platformOK); + + // Check if the port has been specified + + Integer portNum = tcpipSMBConfigBean.getPort(); + if (portNum != null) + { + cifsConfig.setTcpipSMBPort(portNum); + if (cifsConfig.getTcpipSMBPort() <= 0 || cifsConfig.getTcpipSMBPort() >= 65535) + throw new AlfrescoRuntimeException("TCP/IP SMB port out of valid range"); + } + + // Check if IPv6 support should be enabled + + if ( tcpipSMBConfigBean.getIpv6Enabled()) + { + try + { + // Use the IPv6 bind all address + + cifsConfig.setSMBBindAddress( InetAddress.getByName( "::")); + + // DEBUG + + if ( logger.isInfoEnabled()) + logger.info("Enabled CIFS IPv6 bind address for native SMB"); + } + catch ( UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Failed to enable IPv6 bind address, " + ex.getMessage()); + } + } + + } + else + { + + // Disable TCP/IP SMB support + + cifsConfig.setTcpipSMB(false); + } + + // Check if Win32 NetBIOS is enabled + + Win32NetBIOSConfigBean win32NetBIOSConfigBean = cifsConfigBean.getWin32NetBIOS(); + if (win32NetBIOSConfigBean != null) + { + + // Check if the Win32 NetBIOS server name has been specified + + String win32Name = win32NetBIOSConfigBean.getName(); + if (win32Name != null && win32Name.length() > 0) + { + + // Validate the name + + if (win32Name.length() > 16) + throw new AlfrescoRuntimeException("Invalid Win32 NetBIOS name, " + win32Name); + + // Set the Win32 NetBIOS file server name + + cifsConfig.setWin32NetBIOSName(win32Name); + } + + // Check if the Win32 NetBIOS LANA has been specified + + String lanaStr = win32NetBIOSConfigBean.getLana(); + if (lanaStr != null && lanaStr.length() > 0) + { + // Check if the LANA has been specified as an IP address or adapter name + + int lana = -1; + + if (IPAddress.isNumericAddress(lanaStr)) + { + + // Convert the IP address to a LANA id + + lana = Win32NetBIOS.getLANAForIPAddress(lanaStr); + if (lana == -1) + throw new AlfrescoRuntimeException("Failed to convert IP address " + lanaStr + " to a LANA"); + } + else if (lanaStr.length() > 1 && Character.isLetter(lanaStr.charAt(0))) + { + + // Convert the network adapter to a LANA id + + lana = Win32NetBIOS.getLANAForAdapterName(lanaStr); + if (lana == -1) + throw new AlfrescoRuntimeException("Failed to convert network adapter " + lanaStr + + " to a LANA"); + } + else + { + + try + { + lana = Integer.parseInt(lanaStr); + } + catch (NumberFormatException ex) + { + throw new AlfrescoRuntimeException("Invalid win32 NetBIOS LANA specified"); + } + } + + // LANA should be in the range 0-255 + + if (lana < 0 || lana > 255) + throw new AlfrescoRuntimeException("Invalid Win32 NetBIOS LANA number, " + lana); + + // Set the LANA number + + cifsConfig.setWin32LANA(lana); + } + + // Check if the native NetBIOS interface has been specified, either 'winsock' or 'netbios' + + String nativeAPI = win32NetBIOSConfigBean.getApi(); + if (nativeAPI != null && nativeAPI.length() > 0) + { + // Validate the API type + + boolean useWinsock = true; + + if (nativeAPI.equalsIgnoreCase("netbios")) + useWinsock = false; + else if (nativeAPI.equalsIgnoreCase("winsock") == false) + throw new AlfrescoRuntimeException("Invalid NetBIOS API type, spefify 'winsock' or 'netbios'"); + + // Set the NetBIOS API to use + + cifsConfig.setWin32WinsockNetBIOS(useWinsock); + } + + // Force the older NetBIOS API code to be used on 64Bit Windows + + if (cifsConfig.useWinsockNetBIOS() == true && X64.isWindows64()) + { + // Debug + + if (logger.isDebugEnabled()) + logger.debug("Using older Netbios() API code"); + + // Use the older NetBIOS API code + + cifsConfig.setWin32WinsockNetBIOS(false); + } + + // Check if the current operating system is supported by the Win32 + // NetBIOS handler + + String osName = System.getProperty("os.name"); + if (osName.startsWith("Windows") + && (osName.endsWith("95") == false && osName.endsWith("98") == false && osName.endsWith("ME") == false) + && isNativeCodeDisabled() == false) + { + + // Call the Win32NetBIOS native code to make sure it is initialized + + if (Win32NetBIOS.LanaEnumerate() != null) + { + // Enable Win32 NetBIOS + + cifsConfig.setWin32NetBIOS(true); + } + else + { + logger.warn("No NetBIOS LANAs available"); + } + } + else + { + + // Win32 NetBIOS not supported on the current operating system + + cifsConfig.setWin32NetBIOS(false); + } + } + else + { + + // Disable Win32 NetBIOS + + cifsConfig.setWin32NetBIOS(false); + } + + // Check if the Win32 host announcer has been disabled + + if ( !cifsConfigBean.getWin32HostAnnouncerEnabled()) + { + // Switch off the Win32 host announcer + + cifsConfig.setWin32HostAnnouncer( false); + + // Log that host announcements are not enabled + + logger.info("Win32 host announcements not enabled"); + } + else + { + // Check for an announcement interval + Integer interval = cifsConfigBean.getWin32HostAnnounceInterval(); + if (interval != null) + { + cifsConfig.setWin32HostAnnounceInterval(interval); + } + + // Check if the domain name has been set, this is required if the + // host announcer is enabled + + if (cifsConfig.getDomainName() == null) + throw new AlfrescoRuntimeException("Domain name must be specified if host announcement is enabled"); + + // Enable Win32 NetBIOS host announcement + + cifsConfig.setWin32HostAnnouncer(true); + } + + // Check if NetBIOS and/or TCP/IP SMB have been enabled + + if (cifsConfig.hasNetBIOSSMB() == false && cifsConfig.hasTcpipSMB() == false + && cifsConfig.hasWin32NetBIOS() == false) + throw new AlfrescoRuntimeException("NetBIOS SMB, TCP/IP SMB or Win32 NetBIOS must be enabled"); + + // Check if WINS servers are configured + + WINSConfigBean winsConfigBean = cifsConfigBean.getWINSConfig(); + + if (winsConfigBean != null && !winsConfigBean.isAutoDetectEnabled()) + { + + // Get the primary WINS server + + String priWins = winsConfigBean.getPrimary(); + + if (priWins == null || priWins.length() == 0) + throw new AlfrescoRuntimeException("No primary WINS server configured"); + + // Validate the WINS server address + + InetAddress primaryWINS = null; + + try + { + primaryWINS = InetAddress.getByName(priWins); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid primary WINS server address, " + priWins); + } + + // Check if a secondary WINS server has been specified + + String secWins = winsConfigBean.getSecondary(); + InetAddress secondaryWINS = null; + + if (secWins != null && secWins.length() > 0) + { + + // Validate the secondary WINS server address + + try + { + secondaryWINS = InetAddress.getByName(secWins); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid secondary WINS server address, " + secWins); + } + } + + // Set the WINS server address(es) + + cifsConfig.setPrimaryWINSServer(primaryWINS); + if (secondaryWINS != null) + cifsConfig.setSecondaryWINSServer(secondaryWINS); + + // Pass the setting to the NetBIOS session class + + NetBIOSSession.setDefaultWINSServer(primaryWINS); + } + + // Check if WINS is configured, if we are running on Windows and socket based NetBIOS is enabled + + else if (cifsConfig.hasNetBIOSSMB() && getPlatformType() == Platform.Type.WINDOWS && !isNativeCodeDisabled()) + { + // Get the WINS server list + + String winsServers = Win32NetBIOS.getWINSServerList(); + + if (winsServers != null) + { + // Use the first WINS server address for now + + StringTokenizer tokens = new StringTokenizer(winsServers, ","); + String addr = tokens.nextToken(); + + try + { + // Convert to a network address and check if the WINS server is accessible + + InetAddress winsAddr = InetAddress.getByName(addr); + + Socket winsSocket = new Socket(); + InetSocketAddress sockAddr = new InetSocketAddress(winsAddr, RFCNetBIOSProtocol.NAME_PORT); + + winsSocket.connect(sockAddr, 3000); + winsSocket.close(); + + // Set the primary WINS server address + + cifsConfig.setPrimaryWINSServer(winsAddr); + + // Debug + + if (logger.isDebugEnabled()) + logger.debug("Configuring to use WINS server " + addr); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid auto WINS server address, " + addr); + } + catch (IOException ex) + { + if (logger.isDebugEnabled()) + logger.debug("Failed to connect to auto WINS server " + addr); + } + } + } + + // Check for session debug flags + + String flags = cifsConfigBean.getSessionDebugFlags(); + + int sessDbg = 0; + + if (flags != null && flags.length() > 0) + { + + // Parse the flags + + flags = flags.toUpperCase(); + StringTokenizer token = new StringTokenizer(flags, ","); + + while (token.hasMoreTokens()) + { + // Get the current debug flag token + + String dbg = token.nextToken().trim(); + + // Find the debug flag name + + int idx = 0; + + while (idx < m_sessDbgStr.length && m_sessDbgStr[idx].equalsIgnoreCase(dbg) == false) + idx++; + + if (idx > m_sessDbgStr.length) + throw new AlfrescoRuntimeException("Invalid session debug flag, " + dbg); + + // Set the debug flag + + sessDbg += 1 << idx; + } + } + + // Set the session debug flags + + cifsConfig.setSessionDebugFlags(sessDbg); + + // Check if NIO based socket code should be disabled + + if (cifsConfigBean.getDisableNIO()) + { + + // Disable NIO based code + + cifsConfig.setDisableNIOCode(true); + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("NIO based code disabled for CIFS server"); + } + + + // Check if a session timeout is configured + + Integer tmo = cifsConfigBean.getSessionTimeout(); + if (tmo != null) + { + + // Validate the session timeout value + + if (tmo < 0 || tmo > MaxSessionTimeout) + throw new AlfrescoRuntimeException("Session timeout out of range (0 - " + MaxSessionTimeout + ")"); + + // Convert the session timeout to milliseconds + + cifsConfig.setSocketTimeout(tmo * 1000); + } + } + catch (InvalidConfigurationException ex) + { + throw new AlfrescoRuntimeException(ex.getMessage()); + } + } + + /** + * Process the FTP server configuration + */ + protected void processFTPServerConfig() + { + // If the configuration section is not valid then FTP is disabled + + if (ftpConfigBean == null) + { + removeConfigSection(FTPConfigSection.SectionName); + return; + } + + // Check if the server has been disabled + + if (!ftpConfigBean.getServerEnabled()) + { + removeConfigSection(FTPConfigSection.SectionName); + return; + } + + // Create the FTP configuration section + + FTPConfigSection ftpConfig = new FTPConfigSection(this); + + try + { + // Check for a bind address + + String bindText = ftpConfigBean.getBindTo(); + if (bindText != null && bindText.length() > 0 && !bindText.equals(BIND_TO_IGNORE)) + { + + // Validate the bind address + + try + { + + // Check the bind address + + InetAddress bindAddr = InetAddress.getByName(bindText); + + // Set the bind address for the FTP server + + ftpConfig.setFTPBindAddress(bindAddr); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid FTP bindto address, " + bindText); + } + } + + // Check for an FTP server port + + Integer port = ftpConfigBean.getPort(); + if (port != null) + { + ftpConfig.setFTPPort(port); + if (ftpConfig.getFTPPort() <= 0 || ftpConfig.getFTPPort() >= 65535) + throw new AlfrescoRuntimeException("FTP server port out of valid range"); + } + else + { + + // Use the default FTP port + + ftpConfig.setFTPPort(DefaultFTPServerPort); + } + + // Check if anonymous login is allowed + + if (ftpConfigBean.getAllowAnonymous()) + { + + // Enable anonymous login to the FTP server + + ftpConfig.setAllowAnonymousFTP(true); + + // Check if an anonymous account has been specified + + String anonAcc = ftpConfigBean.getAnonymousAccount(); + if (anonAcc != null && anonAcc.length() > 0) + { + + // Set the anonymous account name + + ftpConfig.setAnonymousFTPAccount(anonAcc); + + // Check if the anonymous account name is valid + + if (ftpConfig.getAnonymousFTPAccount() == null || ftpConfig.getAnonymousFTPAccount().length() == 0) + throw new AlfrescoRuntimeException("Anonymous FTP account invalid"); + } + else + { + + // Use the default anonymous account name + + ftpConfig.setAnonymousFTPAccount(DefaultFTPAnonymousAccount); + } + } + else + { + + // Disable anonymous logins + + ftpConfig.setAllowAnonymousFTP(false); + } + + // Check if a root path has been specified + + String rootPath = ftpConfigBean.getRootDirectory(); + if (rootPath != null && rootPath.length() > 0) + { + try + { + + // Parse the path + + new FTPPath(rootPath); + + // Set the root path + + ftpConfig.setFTPRootPath(rootPath); + } + catch (InvalidPathException ex) + { + throw new AlfrescoRuntimeException("Invalid FTP root directory, " + rootPath); + } + } + + // Check for FTP debug flags + + String flags = ftpConfigBean.getDebugFlags(); + int ftpDbg = 0; + + if (flags != null) + { + + // Parse the flags + + flags = flags.toUpperCase(); + StringTokenizer token = new StringTokenizer(flags, ","); + + while (token.hasMoreTokens()) + { + + // Get the current debug flag token + + String dbg = token.nextToken().trim(); + + // Find the debug flag name + + int idx = 0; + + while (idx < m_ftpDebugStr.length && m_ftpDebugStr[idx].equalsIgnoreCase(dbg) == false) + idx++; + + if (idx >= m_ftpDebugStr.length) + throw new AlfrescoRuntimeException("Invalid FTP debug flag, " + dbg); + + // Set the debug flag + + ftpDbg += 1 << idx; + } + + // Set the FTP debug flags + + ftpConfig.setFTPDebug(ftpDbg); + } + + // Check if a character set has been specified + + String charSet = ftpConfigBean.getCharSet(); + if (charSet != null && charSet.length() > 0) + { + + try + { + + // Validate the character set name + + Charset.forName(charSet); + + // Set the FTP character set + + ftpConfig.setFTPCharacterSet(charSet); + } + catch (IllegalCharsetNameException ex) + { + throw new AlfrescoRuntimeException("Illegal character set name, " + charSet); + } + catch (UnsupportedCharsetException ex) + { + throw new AlfrescoRuntimeException("Unsupported character set name, " + charSet); + } + } + + // Check if an authenticator has been specified + + FTPAuthenticator auth = ftpConfigBean.getAuthenticator(); + if (auth != null) + { + + // Initialize and set the authenticator class + + ftpConfig.setAuthenticator(auth); + } + else + throw new AlfrescoRuntimeException("FTP authenticator not specified"); + + // Check if a data port range has been specified + + if ( ftpConfigBean.getDataPortFrom() != 0 && ftpConfigBean.getDataPortTo() != 0) { + + // Range check the data port values + + int rangeFrom = ftpConfigBean.getDataPortFrom(); + int rangeTo = ftpConfigBean.getDataPortTo(); + + if ( rangeFrom != 0 && rangeTo != 0) { + + // Validate the FTP data port range + + if ( rangeFrom < 1024 || rangeFrom > 65535) + throw new InvalidConfigurationException("Invalid FTP data port range from value, " + rangeFrom); + + if ( rangeTo < 1024 || rangeTo > 65535) + throw new InvalidConfigurationException("Invalid FTP data port range to value, " + rangeTo); + + if ( rangeFrom >= rangeTo) + throw new InvalidConfigurationException("Invalid FTP data port range, " + rangeFrom + "-" + rangeTo); + + // Set the FTP data port range + + ftpConfig.setFTPDataPortLow(rangeFrom); + ftpConfig.setFTPDataPortHigh(rangeTo); + + // Log the data port range + + logger.info("FTP server data ports restricted to range " + rangeFrom + ":" + rangeTo); + } + } + + // FTPS parameter parsing + // + // Check if a key store path has been specified + + if ( ftpConfigBean.getKeyStorePath() != null && ftpConfigBean.getKeyStorePath().length() > 0) { + + // Get the path to the key store, check that the file exists + + String keyStorePath = ftpConfigBean.getKeyStorePath(); + File keyStoreFile = new File( keyStorePath); + + if ( keyStoreFile.exists() == false) + throw new InvalidConfigurationException("FTPS key store file does not exist, " + keyStorePath); + else if ( keyStoreFile.isDirectory()) + throw new InvalidConfigurationException("FTPS key store path is a directory, " + keyStorePath); + + // Set the key store path + + ftpConfig.setKeyStorePath( keyStorePath); + } + + // Check if the trust store path has been specified + + if ( ftpConfigBean.getTrustStorePath() != null && ftpConfigBean.getTrustStorePath().length() > 0) { + + // Get the path to the trust store, check that the file exists + + String trustStorePath = ftpConfigBean.getTrustStorePath(); + File trustStoreFile = new File( trustStorePath); + + if ( trustStoreFile.exists() == false) + throw new InvalidConfigurationException("FTPS trust store file does not exist, " + trustStorePath); + else if ( trustStoreFile.isDirectory()) + throw new InvalidConfigurationException("FTPS trust store path is a directory, " + trustStorePath); + + // Set the trust store path + + ftpConfig.setTrustStorePath( trustStorePath); + } + + // Check if the store passphrase has been specified + + if ( ftpConfigBean.getPassphrase() != null && ftpConfigBean.getPassphrase().length() > 0) { + + // Set the store passphrase + + ftpConfig.setPassphrase( ftpConfigBean.getPassphrase()); + } + + // Check if only secure sessions should be allowed to logon + + if ( ftpConfigBean.hasRequireSecureSession()) { + + // Only allow secure sessions to logon to the FTP server + + ftpConfig.setRequireSecureSession( true); + } + + // Check that all the required FTPS parameters have been set + + if ( ftpConfig.getKeyStorePath() != null || ftpConfig.getTrustStorePath() != null || ftpConfig.getPassphrase() != null) { + + // Make sure all parameters are set + + if ( ftpConfig.getKeyStorePath() == null || ftpConfig.getTrustStorePath() == null || ftpConfig.getPassphrase() == null) + throw new InvalidConfigurationException("FTPS configuration requires keyStore, trustStore and storePassphrase to be set"); + } + + // Check if SSLEngine debug output should be enabled + + if ( ftpConfigBean.hasSslEngineDebug()) { + + // Enable SSLEngine debug output + + System.setProperty("javax.net.debug", "ssl,handshake"); + } + } + catch (InvalidConfigurationException ex) + { + throw new AlfrescoRuntimeException(ex.getMessage()); + } + } + + /** + * Process the NFS server configuration + */ + protected void processNFSServerConfig() + { + // If the configuration section is not valid then NFS is disabled + + if (nfsConfigBean == null) + { + removeConfigSection(NFSConfigSection.SectionName); + return; + } + + // Check if the server has been disabled + + if (!nfsConfigBean.getServerEnabled()) + { + removeConfigSection(NFSConfigSection.SectionName); + return; + } + + // Create the NFS configuration section + + NFSConfigSection nfsConfig = new NFSConfigSection(this); + + try + { + // Check if the port mapper is enabled + + if (nfsConfigBean.getPortMapperEnabled()) + nfsConfig.setNFSPortMapper(true); + + // Check for the thread pool size + + Integer poolSize = nfsConfigBean.getThreadPool(); + + if (poolSize != null) + { + + // Range check the pool size value + + if (poolSize < 4) + throw new AlfrescoRuntimeException("NFS thread pool size is below minimum of 4"); + + // Set the thread pool size + + nfsConfig.setNFSThreadPoolSize(poolSize); + } + + // NFS packet pool size + + Integer pktPoolSize = nfsConfigBean.getPacketPool(); + + if (pktPoolSize != null) + { + // Range check the pool size value + + if (pktPoolSize < 10) + throw new AlfrescoRuntimeException("NFS packet pool size is below minimum of 10"); + + if (pktPoolSize < nfsConfig.getNFSThreadPoolSize() + 1) + throw new AlfrescoRuntimeException("NFS packet pool must be at least thread pool size plus one"); + + // Set the packet pool size + + nfsConfig.setNFSPacketPoolSize(pktPoolSize); + } + + // Check for a port mapper server port + + Integer portMapperPort = nfsConfigBean.getPortMapperPort(); + if (portMapperPort != null) + { + nfsConfig.setPortMapperPort(portMapperPort); + if ( nfsConfig.getPortMapperPort() == -1) { + logger.info("NFS portmapper registration disabled"); + } + else { + if (nfsConfig.getPortMapperPort() <= 0 || nfsConfig.getPortMapperPort() >= 65535) + throw new AlfrescoRuntimeException("Port mapper server port out of valid range"); + } + } + + // Check for a mount server port + + Integer mountServerPort = nfsConfigBean.getMountServerPort(); + if (mountServerPort != null) + { + nfsConfig.setMountServerPort(mountServerPort); + if (nfsConfig.getMountServerPort() < 0 || nfsConfig.getMountServerPort() >= 65535) + throw new AlfrescoRuntimeException("Mount server port out of valid range"); + } + + // Check for an NFS server port + + Integer nfsServerPort = nfsConfigBean.getNfsServerPort(); + if (nfsServerPort != null) + { + nfsConfig.setNFSServerPort(nfsServerPort); + if (nfsConfig.getNFSServerPort() < 0 || nfsConfig.getNFSServerPort() >= 65535) + throw new AlfrescoRuntimeException("NFS server port out of valid range"); + } + + // Check for an RPC registration port + + Integer rpcRegisterPort = nfsConfigBean.getRpcRegisterPort(); + if ( rpcRegisterPort != null) + { + nfsConfig.setRPCRegistrationPort( rpcRegisterPort); + if ( nfsConfig.getRPCRegistrationPort() < 0 || nfsConfig.getRPCRegistrationPort() >= 65535) + throw new AlfrescoRuntimeException("RPC registrtion port out of valid range"); + } + + // Check for NFS debug flags + + String flags = nfsConfigBean.getDebugFlags(); + int nfsDbg = 0; + + if (flags != null && flags.length() > 0) + { + + // Parse the flags + + flags = flags.toUpperCase(); + StringTokenizer token = new StringTokenizer(flags, ","); + + while (token.hasMoreTokens()) + { + + // Get the current debug flag token + + String dbg = token.nextToken().trim(); + + // Find the debug flag name + + int idx = 0; + + while (idx < m_nfsDebugStr.length && m_nfsDebugStr[idx].equalsIgnoreCase(dbg) == false) + idx++; + + if (idx >= m_nfsDebugStr.length) + throw new AlfrescoRuntimeException("Invalid NFS debug flag, " + dbg); + + // Set the debug flag + + nfsDbg += 1 << idx; + } + + // Set the NFS debug flags + + nfsConfig.setNFSDebug(nfsDbg); + } + + // Check if mount server debug output is enabled + + if (nfsConfigBean.getMountServerDebug()) + nfsConfig.setMountServerDebug(true); + + // Check if portmapper debug output is enabled + + if (nfsConfigBean.getPortMapperDebug()) + nfsConfig.setPortMapperDebug(true); + + // Create the RPC authenticator + RpcAuthenticator rpcAuthenticator = nfsConfigBean.getRpcAuthenticator(); + if (rpcAuthenticator != null) + { + nfsConfig.setRpcAuthenticator(rpcAuthenticator); + } + else + throw new AlfrescoRuntimeException("RPC authenticator configuration missing, require user mappings"); + } + catch (InvalidConfigurationException ex) + { + throw new AlfrescoRuntimeException(ex.getMessage()); + } + } + + /** + * Process the filesystems configuration + */ + protected void processFilesystemsConfig() + { + // Create the filesystems configuration section + + FilesystemsConfigSection fsysConfig = new FilesystemsConfigSection(this); + + // Access the security configuration section + + SecurityConfigSection secConfig = (SecurityConfigSection) getConfigSection(SecurityConfigSection.SectionName); + + // Process the filesystems list + + if (this.filesystemContexts != null) + { + + // Add the filesystems + + for (DeviceContext filesystem : this.filesystemContexts) + { + + // Get the current filesystem configuration + + try + { + // Check the filesystem type and use the appropriate driver + + DiskSharedDevice filesys = null; + + if (filesystem instanceof AVMContext) + { + // Create a new filesystem driver instance and register a context for + // the new filesystem + + ExtendedDiskInterface filesysDriver = getAvmDiskInterface(); + DiskDeviceContext diskCtx = (DiskDeviceContext) filesystem; + + if(clusterConfigBean != null && clusterConfigBean.getClusterEnabled()) + { + if(logger.isDebugEnabled()) + { + logger.debug("start hazelcast cache : " + clusterConfigBean.getClusterName() + ", shareName: "+ diskCtx.getShareName()); + } + GenericConfigElement hazelConfig = createClusterConfig(diskCtx.getShareName()); + HazelCastClusterFileStateCache hazel = new HazelCastClusterFileStateCache(); + hazel.initializeCache(hazelConfig, this); + diskCtx.setStateCache(hazel); + } + else + { + // Check if the filesystem uses the file state cache, if so then add to the file state reaper + StandaloneFileStateCache standaloneCache = new StandaloneFileStateCache(); + standaloneCache.initializeCache( new GenericConfigElement( ""), this); + diskCtx.setStateCache(standaloneCache); + } + if ( diskCtx.hasStateCache()) { + + // Register the state cache with the reaper thread + + fsysConfig.addFileStateCache( filesystem.getDeviceName(), diskCtx.getStateCache()); + } + + filesysDriver.registerContext(filesystem); + + // Create the shared filesystem + + filesys = new DiskSharedDevice(filesystem.getDeviceName(), filesysDriver, (AVMContext)filesystem); + filesys.setConfiguration( this); + // Start the filesystem + + ((AVMContext)filesystem).startFilesystem(filesys); + } + else + { + // Create a new filesystem driver instance and register a context for + // the new filesystem + + ExtendedDiskInterface filesysDriver = getRepoDiskInterface(); + ContentContext filesysContext = (ContentContext) filesystem; + + if(clusterConfigBean != null && clusterConfigBean.getClusterEnabled()) + { + if(logger.isDebugEnabled()) + { + logger.debug("start hazelcast cache : " + clusterConfigBean.getClusterName() + ", shareName: "+ filesysContext.getShareName()); + } + GenericConfigElement hazelConfig = createClusterConfig(filesysContext.getShareName()); + HazelCastClusterFileStateCache hazel = new HazelCastClusterFileStateCache(); + hazel.initializeCache(hazelConfig, this); + filesysContext.setStateCache(hazel); + } + else + { + // Create state cache here and inject + StandaloneFileStateCache standaloneCache = new StandaloneFileStateCache(); + standaloneCache.initializeCache( new GenericConfigElement( ""), this); + filesysContext.setStateCache(standaloneCache); + } + + if ( filesysContext.hasStateCache()) { + + // Register the state cache with the reaper thread + + fsysConfig.addFileStateCache( filesystem.getDeviceName(), filesysContext.getStateCache()); + + // Create the lock manager for the context. + FileStateLockManager lockMgr = new FileStateLockManager(filesysContext.getStateCache()); + filesysContext.setLockManager(lockMgr); + filesysContext.setOpLockManager(lockMgr); + } + + filesysDriver.registerContext(filesystem); + + // Check if an access control list has been specified + + AccessControlList acls = null; + AccessControlListBean accessControls = filesysContext.getAccessControlList(); + if (accessControls != null) + { + // Parse the access control list + acls = accessControls.toAccessControlList(secConfig); + } + else if (secConfig.hasGlobalAccessControls()) + { + + // Use the global access control list for this disk share + acls = secConfig.getGlobalAccessControls(); + } + + // Create the shared filesystem + + filesys = new DiskSharedDevice(filesystem.getDeviceName(), filesysDriver, filesysContext); + filesys.setConfiguration( this); + + // Add any access controls to the share + + filesys.setAccessControlList(acls); + + + + // Check if change notifications should be enabled + + if ( filesysContext.getDisableChangeNotifications() == false) + filesysContext.enableChangeHandler( true); + + // Start the filesystem + + filesysContext.startFilesystem(filesys); + } + + // Add the new filesystem + + fsysConfig.addShare(filesys); + } + catch (DeviceContextException ex) + { + throw new AlfrescoRuntimeException("Error creating filesystem " + filesystem.getDeviceName(), ex); + } + catch (InvalidConfigurationException ex) + { + throw new AlfrescoRuntimeException(ex.getMessage(), ex); + } + } + } + else + { + // No filesystems defined + + logger.warn("No filesystems defined"); + } + + // Check if shares should be added for all AVM stores + if (this.avmAllStores && getAvmDiskInterface() != null) + { + // Get the list of store names + + AVMDiskDriver avmDriver = (AVMDiskDriver) getAvmDiskInterface(); + StringList storeNames = avmDriver.getAVMStoreNames(); + + // Add shares for each of the store names, if the share name does not already exist + + if (storeNames != null && storeNames.numberOfStrings() > 0) + { + // Add a share for each store + + for (int i = 0; i < storeNames.numberOfStrings(); i++) + { + String storeName = storeNames.getStringAt(i); + + // Check if a share of the same name already exists + + if (fsysConfig.getShares().findShare(storeName, ShareType.DISK, true) == null) + { + // Create the new share for the store + + AVMContext avmContext = new AVMContext(storeName, storeName + ":/", AVMContext.VERSION_HEAD); +// avmContext.enableStateCache(this, true); + + // Create the shared filesystem + + DiskSharedDevice filesys = new DiskSharedDevice(storeName, avmDriver, avmContext); + filesys.setConfiguration( this); + + fsysConfig.addShare( filesys); + + // DEBUG + + if (logger.isDebugEnabled()) + logger.debug("Added AVM share " + storeName); + } + } + } + } + + + // home folder share mapper could be declared in security config + } + + /** + * Process the security configuration + */ + protected void processSecurityConfig() + { + // Create the security configuration section + + SecurityConfigSection secConfig = new SecurityConfigSection(this); + + try + { + // Check if global access controls have been specified + + AccessControlListBean accessControls = securityConfigBean.getGlobalAccessControl(); + + if (accessControls != null) + { + // Parse the access control list + AccessControlList acls = accessControls.toAccessControlList(secConfig); + if (acls != null) + secConfig.setGlobalAccessControls(acls); + } + + + // Check if a JCE provider class has been specified + + String jceProvider = securityConfigBean.getJCEProvider(); + if (jceProvider != null && jceProvider.length() > 0) + { + + // Set the JCE provider + + secConfig.setJCEProvider(jceProvider); + } + else + { + // Use the default Bouncy Castle JCE provider + + secConfig.setJCEProvider("org.bouncycastle.jce.provider.BouncyCastleProvider"); + } + + // Check if a share mapper has been specified + + ShareMapper shareMapper = securityConfigBean.getShareMapper(); + if (shareMapper != null) + { + // Associate the share mapper + secConfig.setShareMapper(shareMapper); + } + else + { + // Check if the tenant service is enabled + if (m_tenantService != null && m_tenantService.isEnabled()) + { + // Initialize the multi-tenancy share mapper + + secConfig.setShareMapper("org.alfresco.filesys.alfresco.MultiTenantShareMapper", + new GenericConfigElement("shareMapper")); + + } + } + + // Check if any domain mappings have been specified + + List mappings = securityConfigBean.getDomainMappings(); + if (mappings != null) + { + DomainMapping mapping = null; + + for (DomainMappingConfigBean domainMap : mappings) + { + // Get the domain name + + String name = domainMap.getName(); + + // Check if the domain is specified by subnet or range + + String subnetStr = domainMap.getSubnet(); + String rangeFromStr; + if (subnetStr != null && subnetStr.length() > 0) + { + String maskStr = domainMap.getMask(); + + // Parse the subnet and mask, to validate and convert to int values + + int subnet = IPAddress.parseNumericAddress(subnetStr); + int mask = IPAddress.parseNumericAddress(maskStr); + + if (subnet == 0 || mask == 0) + throw new AlfrescoRuntimeException("Invalid subnet/mask for domain mapping " + name); + + // Create the subnet domain mapping + + mapping = new SubnetDomainMapping(name, subnet, mask); + } + else if ((rangeFromStr = domainMap.getRangeFrom()) != null && rangeFromStr.length() > 0) + { + String rangeToStr = domainMap.getRangeTo(); + + // Parse the range from/to values and convert to int values + + int rangeFrom = IPAddress.parseNumericAddress(rangeFromStr); + int rangeTo = IPAddress.parseNumericAddress(rangeToStr); + + if (rangeFrom == 0 || rangeTo == 0) + throw new AlfrescoRuntimeException("Invalid address range domain mapping " + name); + + // Create the subnet domain mapping + + mapping = new RangeDomainMapping(name, rangeFrom, rangeTo); + } + else + throw new AlfrescoRuntimeException("Invalid domain mapping specified"); + + // Add the domain mapping + + secConfig.addDomainMapping(mapping); + } + } + } + catch (InvalidConfigurationException ex) + { + throw new AlfrescoRuntimeException(ex.getMessage()); + } + } + + /** + * Process the core server configuration + * + * @exception InvalidConfigurationException + */ + protected void processCoreServerConfig() throws InvalidConfigurationException + { + // Create the core server configuration section + + CoreServerConfigSection coreConfig = new CoreServerConfigSection(this); + + // Check if the CIFS server is not enabled, do not create the thread/memory pools + + if ( cifsConfigBean == null || cifsConfigBean.getServerEnabled() == false) + return; + + // Check if the server core element has been specified + + if (coreServerConfigBean == null) + { + + // Configure a default memory pool + + coreConfig.setMemoryPool(DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc); + + // Configure a default thread pool size + + coreConfig.setThreadPool(DefaultThreadPoolInit, DefaultThreadPoolMax); + + threadPool = coreConfig.getThreadPool(); + + return; + } + + // Check if the thread pool size has been specified + + Integer initSize = coreServerConfigBean.getThreadPoolInit(); + if (initSize == null) + { + initSize = DefaultThreadPoolInit; + } + Integer maxSize = coreServerConfigBean.getThreadPoolMax(); + if (maxSize == null) + { + maxSize = DefaultThreadPoolMax; + } + + // Range check the thread pool size + + if (initSize < ThreadRequestPool.MinimumWorkerThreads) + throw new InvalidConfigurationException("Thread pool size below minimum allowed size"); + + if (initSize > ThreadRequestPool.MaximumWorkerThreads) + throw new InvalidConfigurationException("Thread pool size above maximum allowed size"); + + // Range check the maximum thread pool size + + if (maxSize < ThreadRequestPool.MinimumWorkerThreads) + throw new InvalidConfigurationException("Thread pool maximum size below minimum allowed size"); + + if (maxSize > ThreadRequestPool.MaximumWorkerThreads) + throw new InvalidConfigurationException("Thread pool maximum size above maximum allowed size"); + + if (maxSize < initSize) + throw new InvalidConfigurationException("Initial size is larger than maxmimum size"); + + // Configure the thread pool + + coreConfig.setThreadPool(initSize, maxSize); + + threadPool = coreConfig.getThreadPool(); + + // Check if thread pool debug output is enabled + + if (coreServerConfigBean.getThreadPoolDebug()) + coreConfig.getThreadPool().setDebug(true); + + // Check if the packet sizes/allocations have been specified + + List packetSizes = coreServerConfigBean.getMemoryPacketSizes(); + if (packetSizes != null) + { + + // Calculate the array size for the packet size/allocation arrays + + int elemCnt = packetSizes.size(); + + // Create the packet size, initial allocation and maximum allocation arrays + + int[] pktSizes = new int[elemCnt]; + int[] initSizes = new int[elemCnt]; + int[] maxSizes = new int[elemCnt]; + + int elemIdx = 0; + + // Process the packet size elements + for (MemoryPacketConfigBean curChild : packetSizes) + { + + // Get the packet size + + int pktSize = -1; + + Long pktSizeLong = curChild.getSize(); + if (pktSizeLong == null) + throw new InvalidConfigurationException("Memory pool packet size not specified"); + + // Parse the packet size + + try + { + pktSize = MemorySize.getByteValueInt(pktSizeLong.toString()); + } + catch (NumberFormatException ex) + { + throw new InvalidConfigurationException("Memory pool packet size, invalid size value, " + + pktSizeLong); + } + + // Make sure the packet sizes have been specified in ascending order + + if (elemIdx > 0 && pktSizes[elemIdx - 1] >= pktSize) + throw new InvalidConfigurationException( + "Invalid packet size specified, less than/equal to previous packet size"); + + // Get the initial allocation for the current packet size + Integer initAlloc = curChild.getInit(); + if (initAlloc == null) + throw new InvalidConfigurationException("Memory pool initial allocation not specified"); + + // Range check the initial allocation + + if (initAlloc < MemoryPoolMinimumAllocation) + throw new InvalidConfigurationException("Initial memory pool allocation below minimum of " + + MemoryPoolMinimumAllocation); + + if (initAlloc > MemoryPoolMaximumAllocation) + throw new InvalidConfigurationException("Initial memory pool allocation above maximum of " + + MemoryPoolMaximumAllocation); + + // Get the maximum allocation for the current packet size + + Integer maxAlloc = curChild.getMax(); + if (maxAlloc == null) + throw new InvalidConfigurationException("Memory pool maximum allocation not specified"); + + // Range check the maximum allocation + + if (maxAlloc < MemoryPoolMinimumAllocation) + throw new InvalidConfigurationException("Maximum memory pool allocation below minimum of " + + MemoryPoolMinimumAllocation); + + if (initAlloc > MemoryPoolMaximumAllocation) + throw new InvalidConfigurationException("Maximum memory pool allocation above maximum of " + + MemoryPoolMaximumAllocation); + + // Set the current packet size elements + + pktSizes[elemIdx] = pktSize; + initSizes[elemIdx] = initAlloc; + maxSizes[elemIdx] = maxAlloc; + + elemIdx++; + } + + // Check if all elements were used in the packet size/allocation arrays + + if (elemIdx < pktSizes.length) + { + + // Re-allocate the packet size/allocation arrays + + int[] newPktSizes = new int[elemIdx]; + int[] newInitSizes = new int[elemIdx]; + int[] newMaxSizes = new int[elemIdx]; + + // Copy the values to the shorter arrays + + System.arraycopy(pktSizes, 0, newPktSizes, 0, elemIdx); + System.arraycopy(initSizes, 0, newInitSizes, 0, elemIdx); + System.arraycopy(maxSizes, 0, newMaxSizes, 0, elemIdx); + + // Move the new arrays into place + + pktSizes = newPktSizes; + initSizes = newInitSizes; + maxSizes = newMaxSizes; + } + + // Configure the memory pool + + coreConfig.setMemoryPool(pktSizes, initSizes, maxSizes); + } + else + { + + // Configure a default memory pool + + coreConfig.setMemoryPool(DefaultMemoryPoolBufSizes, DefaultMemoryPoolInitAlloc, DefaultMemoryPoolMaxAlloc); + } + } + + /** + * Initialise a runtime context - not configured through spring e.g MT. + * + * TODO - what about desktop actions etc? + * + * @param diskCtx + */ + public void initialiseRuntimeContext(AlfrescoContext diskCtx) + { + if (diskCtx.getStateCache() == null) { + + // Set the state cache, use a hard coded standalone cache for now + FilesystemsConfigSection filesysConfig = (FilesystemsConfigSection) this.getConfigSection( FilesystemsConfigSection.SectionName); + + if ( filesysConfig != null) + { + + try + { + if(clusterConfigBean != null && clusterConfigBean.getClusterEnabled()) + { + if(logger.isDebugEnabled()) + { + logger.debug("start hazelcast cache : " + clusterConfigBean.getClusterName() + ", shareName: "+ diskCtx.getShareName()); + } + GenericConfigElement hazelConfig = createClusterConfig(diskCtx.getShareName()); + HazelCastClusterFileStateCache hazel = new HazelCastClusterFileStateCache(); + hazel.initializeCache(hazelConfig, this); + diskCtx.setStateCache(hazel); + } + else + { + // Create a standalone state cache + StandaloneFileStateCache standaloneCache = new StandaloneFileStateCache(); + standaloneCache.initializeCache( new GenericConfigElement( ""), this); + filesysConfig.addFileStateCache( diskCtx.getDeviceName(), standaloneCache); + diskCtx.setStateCache( standaloneCache); + } + + FileStateLockManager lockMgr = new FileStateLockManager(diskCtx.getStateCache()); + diskCtx.setLockManager(lockMgr); + diskCtx.setOpLockManager(lockMgr); + } + catch ( InvalidConfigurationException ex) + { + throw new AlfrescoRuntimeException( "Failed to initialize standalone state cache for " + diskCtx.getDeviceName()); + } + } + } + } + + + @Override + protected void processClusterConfig() throws InvalidConfigurationException + { + +// Done by org.alfresco.jlan.server.config.ServerConfiguration.closeConfiguration +// /** +// * Close the old hazelcast configuration +// */ +// ClusterConfigSection secConfig = (ClusterConfigSection) getConfigSection(ClusterConfigSection.SectionName); +// { +// if(secConfig != null) +// { +// secConfig.closeConfig(); +// } +// } + + if (clusterConfigBean == null || !clusterConfigBean.getClusterEnabled()) + { + removeConfigSection(ClusterConfigSection.SectionName); + logger.info("Filesystem cluster cache not enabled"); + return; + } + + String clusterName = clusterConfigBean.getClusterName(); + if (clusterName == null || clusterName.length() == 0) + { + throw new InvalidConfigurationException("Cluster name not specified or invalid"); + } + + String clusterFile = clusterConfigBean.getConfigFile(); + if (clusterFile == null || clusterFile.length() == 0) + { + throw new InvalidConfigurationException("Cluster config file not specified or invalid"); + } + + // New Hazelcast instance created here within the ClusterConfigSection ClusterConfigSection jlanClusterConfig = new ClusterConfigSection(this); try @@ -2253,8 +2261,8 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean throw new InvalidConfigurationException("Unable to start filsystem cluster", e); } } - - + + private GenericConfigElement createClusterConfig(String topicName) throws InvalidConfigurationException { GenericConfigElement config = new GenericConfigElement("hazelcastStateCache"); @@ -2285,6 +2293,13 @@ public class ServerConfigurationBean extends AbstractServerConfigurationBean config.addChild(nearCacheCfg); } return config; - } - -} + } + + @Override + public void destroy() throws Exception + { + threadPool.shutdownThreadPool(); + threadPool = null; + } + +} diff --git a/source/java/org/alfresco/filesys/repo/ContentContext.java b/source/java/org/alfresco/filesys/repo/ContentContext.java index 43984a7b41..66b4f28b0c 100644 --- a/source/java/org/alfresco/filesys/repo/ContentContext.java +++ b/source/java/org/alfresco/filesys/repo/ContentContext.java @@ -32,6 +32,7 @@ import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.DiskSharedDevice; import org.alfresco.jlan.server.filesys.FileName; import org.alfresco.jlan.server.filesys.FileSystem; +import org.alfresco.jlan.server.filesys.cache.FileStateLockManager; import org.alfresco.jlan.server.filesys.quota.QuotaManagerException; import org.alfresco.jlan.server.thread.ThreadRequestPool; import org.alfresco.service.cmr.repository.NodeRef; @@ -66,6 +67,10 @@ public class ContentContext extends AlfrescoContext private AccessControlListBean m_accessControlList; + // File state based lock/oplock manager + + private FileStateLockManager m_lockManager; + // Enable/disable oplocks private boolean m_oplocksDisabled; @@ -206,7 +211,15 @@ public class ContentContext extends AlfrescoContext if (m_rootPath == null || m_rootPath.length() == 0) { throw new AlfrescoRuntimeException("Device missing rootPath"); - } + } + + // Enable file state caching + + getStateCache().setCaseSensitive( false); + + // Create the file state based lock manager + + m_lockManager = new FileStateLockManager( getStateCache()); } /** @@ -279,6 +292,15 @@ public class ContentContext extends AlfrescoContext return m_oplocksDisabled; } + /** + * Return the lock manager + * + * @return FileStateLockManager + */ + public FileStateLockManager getLockManager() { + return m_lockManager; + } + /** * Determine if change notifications are disabled * @@ -385,6 +407,15 @@ public class ContentContext extends AlfrescoContext if ( coreConfig != null) m_threadPool = coreConfig.getThreadPool(); + // Start the lock manager, use the thread pool if available + + if ( getLockManager() != null) { + + // Start the lock manager + + m_lockManager.startLockManager( "OplockExpire_" + share.getName(), m_threadPool); + } + // Start the node monitor, if enabled if ( m_nodeMonitor != null) diff --git a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java index 35e3980837..ccacc7e63d 100644 --- a/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java +++ b/source/java/org/alfresco/filesys/repo/ContentDiskDriver.java @@ -200,8 +200,8 @@ public class ContentDiskDriver extends AlfrescoTxDiskDriver implements DiskInter private BehaviourFilter policyBehaviourFilter; private NodeMonitorFactory m_nodeMonitorFactory; - private static FileStateLockManager _lockManager; - + + /** * Class constructor * @@ -774,11 +774,11 @@ public class ContentDiskDriver extends AlfrescoTxDiskDriver implements DiskInter logger.info("Locked files will be marked as offline"); } + + // Enable file state caching -// // Enable file state caching -// // context.enableStateCache(serverConfig, true); - + // Install the node service monitor if ( !context.getDisableNodeMonitor() && m_nodeMonitorFactory != null) { @@ -789,10 +789,6 @@ public class ContentDiskDriver extends AlfrescoTxDiskDriver implements DiskInter context.setNodeMonitor( nodeMonitor); } - // Create the lock manager - - _lockManager = new FileStateLockManager( context.getStateCache()); - // Check if oplocks are enabled if ( context.getDisableOplocks() == true) @@ -1719,7 +1715,8 @@ public class ContentDiskDriver extends AlfrescoTxDiskDriver implements DiskInter // Check if the current file open allows the required shared access boolean nosharing = false; - + String noshrReason = null; + // TEST if ( params.getAccessMode() == AccessMode.NTFileGenericExecute && params.getPath().toLowerCase().endsWith( ".exe") == false) { @@ -1736,45 +1733,53 @@ public class ContentDiskDriver extends AlfrescoTxDiskDriver implements DiskInter if ( fstate.getOpenCount() > 0) { - // Check for impersonation security level from the original process that opened the file - - if ( params.getSecurityLevel() == WinNT.SecurityImpersonation && params.getProcessId() == fstate.getProcessId()) - nosharing = false; - - // Check if the caller wants read access, check the sharing mode - - else if ( params.isReadOnlyAccess() && (fstate.getSharedAccess() & SharingMode.READ) != 0) - nosharing = false; - - // Check if the caller wants write access, check the sharing mode - - else if (( params.isReadWriteAccess() || params.isWriteOnlyAccess()) && (fstate.getSharedAccess() & SharingMode.WRITE) == 0) - { - // DEBUG - + // Check for impersonation security level from the original process that opened the file + + if ( params.getSecurityLevel() == WinNT.SecurityImpersonation && params.getProcessId() == fstate.getProcessId()) + nosharing = false; + + // Check if the caller wants read access, check the sharing mode + // Check if the caller wants write access, check if the sharing mode allows write + + else if ( params.isReadOnlyAccess() && (fstate.getSharedAccess() & SharingMode.READ) != 0) + nosharing = false; + + // Check if the caller wants write access, check the sharing mode + + else if (( params.isReadWriteAccess() || params.isWriteOnlyAccess()) && (fstate.getSharedAccess() & SharingMode.WRITE) == 0) + { + nosharing = true; + noshrReason = "Sharing mode disallows write"; + + // DEBUG + if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE)) - logger.debug("Sharing mode disallows write access path=" + params.getPath()); - - // Access not allowed - - throw new AccessDeniedException( "Sharing mode (write)"); - } - - // Check if the file has been opened for exclusive access - - else if ( fstate.getSharedAccess() == SharingMode.NOSHARING) - nosharing = true; - - // Check if the required sharing mode is allowed by the current file open - - else if ( ( fstate.getSharedAccess() & params.getSharedAccess()) != params.getSharedAccess()) - nosharing = true; - - // Check if the caller wants exclusive access to the file - - else if ( params.getSharedAccess() == SharingMode.NOSHARING) - nosharing = true; - + logger.debug("Sharing mode disallows write access path=" + params.getPath()); + } + + // Check if the file has been opened for exclusive access + + else if ( fstate.getSharedAccess() == SharingMode.NOSHARING) { + nosharing = true; + noshrReason = "Sharing mode exclusive"; + } + + // Check if the required sharing mode is allowed by the current file open + + else if ((fstate.getSharedAccess() & params.getSharedAccess()) != params.getSharedAccess()) { + nosharing = true; + noshrReason = "Sharing mode mismatch"; + + if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE)) + logger.debug("Local share mode=0x" + Integer.toHexString(fstate.getSharedAccess()) + ", params share mode=0x" + Integer.toHexString(params.getSharedAccess())); + } + + // Check if the caller wants exclusive access to the file + + else if ( params.getSharedAccess() == SharingMode.NOSHARING) { + nosharing = true; + noshrReason = "Requestor wants exclusive mode"; + } } // Check if the file allows shared access @@ -1786,7 +1791,7 @@ public class ContentDiskDriver extends AlfrescoTxDiskDriver implements DiskInter // DEBUG if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE)) - logger.debug("Sharing violation path=" + params.getPath() + ", sharing=0x" + Integer.toHexString(fstate.getSharedAccess())); + logger.debug("Sharing violation path=" + params.getPath() + ", sharing=0x" + Integer.toHexString(fstate.getSharedAccess()) + ",reason=" + noshrReason); // File is locked by another user @@ -4024,7 +4029,8 @@ public class ContentDiskDriver extends AlfrescoTxDiskDriver implements DiskInter * @return LockManager */ public LockManager getLockManager(SrvSession sess, TreeConnection tree) { - return _lockManager; + ContentContext ctx = (ContentContext) tree.getContext(); + return ctx.getLockManager(); } /** @@ -4035,7 +4041,8 @@ public class ContentDiskDriver extends AlfrescoTxDiskDriver implements DiskInter * @return OpLockManager */ public OpLockManager getOpLockManager(SrvSession sess, TreeConnection tree) { - return _lockManager; + ContentContext ctx = (ContentContext) tree.getContext(); + return ctx.getLockManager(); } /** diff --git a/source/java/org/alfresco/filesys/repo/ContentQuotaManager.java b/source/java/org/alfresco/filesys/repo/ContentQuotaManager.java index 012bc3ca10..5dcb67bc67 100644 --- a/source/java/org/alfresco/filesys/repo/ContentQuotaManager.java +++ b/source/java/org/alfresco/filesys/repo/ContentQuotaManager.java @@ -21,6 +21,7 @@ package org.alfresco.filesys.repo; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; +import java.util.Map; import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.filesys.DiskDeviceContext; @@ -72,8 +73,8 @@ public class ContentQuotaManager implements QuotaManager, Runnable { // Track live usage of users that are writing files - private HashMap m_liveUsage; - private Object m_addDetailsLock = new Object(); + private Map m_liveUsage; + private Object m_liveUsageLock = new Object(); // User details inactivity checker thread @@ -141,10 +142,12 @@ public class ContentQuotaManager implements QuotaManager, Runnable { // Check if there is a live usage record for the user UserQuotaDetails userQuota = getQuotaDetails(sess, true); - if ( userQuota != null) - { - return userQuota.getAvailableSpace(); - } + if ( userQuota != null) { + synchronized (userQuota) { + return userQuota.getAvailableSpace(); + } + } + // No quota details available return 0L; @@ -177,10 +180,10 @@ public class ContentQuotaManager implements QuotaManager, Runnable { // Check if the user has a usage quota - if ( userQuota.hasUserQuota()) { + synchronized ( userQuota) { - synchronized ( userQuota) { - + if ( userQuota.hasUserQuota()) { + // Check if the user has enough free space allocation if ( alloc > 0 && userQuota.getAvailableSpace() >= alloc) { @@ -188,12 +191,9 @@ public class ContentQuotaManager implements QuotaManager, Runnable { allowedAlloc = alloc; } } - } - else { + else { - // Update the live usage - - synchronized ( userQuota) { + // Update the live usage userQuota.addToCurrentUsage( alloc); allowedAlloc = alloc; } @@ -308,12 +308,14 @@ public class ContentQuotaManager implements QuotaManager, Runnable { } // Clear out the live usage details - - m_liveUsage.clear(); + synchronized (m_liveUsageLock) + { + m_liveUsage.clear(); + m_shutdown = true; + } // Shutdown the checker thread - m_shutdown = true; m_thread.interrupt(); } @@ -326,37 +328,40 @@ public class ContentQuotaManager implements QuotaManager, Runnable { */ private UserQuotaDetails getQuotaDetails(SrvSession sess, boolean loadDetails) { - UserQuotaDetails userQuota = null; + synchronized (m_liveUsageLock) { + + UserQuotaDetails userQuota = null; String userName = AuthenticationUtil.getFullyAuthenticatedUser(); - + if ( sess != null && userName != null) { - // Get the live usage values - + // Get the live usage values userQuota = m_liveUsage.get(userName); if ( userQuota == null && loadDetails == true) { - // User is not in the live tracking table, load details for the user + // User is not in the live tracking table, load details for the user + try { logger.debug("user is not in cache - load details"); userQuota = loadUsageDetails(userName); - } + } catch ( QuotaManagerException ex) { - if ( logger.isDebugEnabled()) + if ( logger.isDebugEnabled()) { logger.debug("Unable to load usage details", ex); } - } - } - } - - // Return the user quota details - - return userQuota; + } + } + } + + // Return the user quota details + + return userQuota; + } } /** @@ -396,8 +401,6 @@ public class ContentQuotaManager implements QuotaManager, Runnable { // Add the details to the live tracking table - synchronized ( m_addDetailsLock) { - // Check if another thread has added the details UserQuotaDetails details = m_liveUsage.get( userName); @@ -409,7 +412,6 @@ public class ContentQuotaManager implements QuotaManager, Runnable { { m_liveUsage.put( userName, quotaDetails); } - } // DEBUG @@ -479,61 +481,66 @@ public class ContentQuotaManager implements QuotaManager, Runnable { } // Check if there are any user quota details to check - - if ( m_liveUsage != null && m_liveUsage.size() > 0) + synchronized (m_liveUsageLock) { - try + if ( m_liveUsage != null && m_liveUsage.size() > 0) { - // Timestamp to check if the quota details is inactive + try + { + // Timestamp to check if the quota details is inactive - long checkTime = System.currentTimeMillis() - UserQuotaExpireInterval; + long checkTime = System.currentTimeMillis() - UserQuotaExpireInterval; - // Loop through the user quota details + // Loop through the user quota details - removeNameList.remoteAllStrings(); - Iterator userNames = m_liveUsage.keySet().iterator(); + removeNameList.remoteAllStrings(); + Iterator userNames = m_liveUsage.keySet().iterator(); - while ( userNames.hasNext()) { + while ( userNames.hasNext()) { - // Get the user quota details and check if it has been inactive in the last check interval + // Get the user quota details and check if it has been inactive in the last check interval - String userName = userNames.next(); - UserQuotaDetails quotaDetails = m_liveUsage.get( userName); + String userName = userNames.next(); + UserQuotaDetails quotaDetails = m_liveUsage.get( userName); - if ( quotaDetails.getLastUpdated() < checkTime) { - - // Add the user name to the remove list, inactive - - removeNameList.addString( userName); - } - } + synchronized (quotaDetails) { + if ( quotaDetails.getLastUpdated() < checkTime) { + + // Add the user name to the remove list, inactive + + removeNameList.addString( userName); + } + } + } - // Remove inactive records from the live quota tracking + // Remove inactive records from the live quota tracking while ( removeNameList.numberOfStrings() > 0) { - // Get the current user name and remove the record + // Get the current user name and remove the record - String userName = removeNameList.removeStringAt( 0); - UserQuotaDetails quotaDetails = m_liveUsage.remove( userName); + String userName = removeNameList.removeStringAt( 0); + UserQuotaDetails quotaDetails = m_liveUsage.remove( userName); - // DEBUG + // DEBUG - if ( logger.isDebugEnabled()) - logger.debug("Removed inactive usage tracking, " + quotaDetails); + if ( logger.isDebugEnabled()) + logger.debug("Removed inactive usage tracking, " + quotaDetails); + } + } + catch (Exception ex) + { + // Log errors if not shutting down + + if ( m_shutdown == false) + logger.debug(ex); } } - catch (Exception ex) - { - // Log errors if not shutting down - - if ( m_shutdown == false) - logger.debug(ex); - } } - } - } + } + + } public void setContentService(ContentService contentService) { diff --git a/source/java/org/alfresco/repo/audit/AuditMethodInterceptor.java b/source/java/org/alfresco/repo/audit/AuditMethodInterceptor.java index c61923da3a..b0f1ffda89 100644 --- a/source/java/org/alfresco/repo/audit/AuditMethodInterceptor.java +++ b/source/java/org/alfresco/repo/audit/AuditMethodInterceptor.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.ThreadPoolExecutor; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.StackTraceUtil; import org.alfresco.repo.audit.model.AuditApplication; import org.alfresco.repo.domain.schema.SchemaBootstrap; @@ -216,8 +217,8 @@ public class AuditMethodInterceptor implements MethodInterceptor } catch (Throwable e) { - // Failure to audit should not break the invocation - logger.error( + // Failure to audit must stop the process: ALF-11139 + throw new AlfrescoRuntimeException( "Failed to audit pre-invocation: \n" + " Invocation: " + mi, e); @@ -243,8 +244,8 @@ public class AuditMethodInterceptor implements MethodInterceptor } catch (Throwable e) { - // Failure to audit should not break the invocation - logger.error( + // Failure to audit must stop the process: ALF-11139 + throw new AlfrescoRuntimeException( "Failed to audit post-invocation: \n" + " Invocation: " + mi, e); diff --git a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java index 98110b8e25..d5abca02f9 100644 --- a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java +++ b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java @@ -367,7 +367,7 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService throw new CheckOutCheckInServiceException(MSG_ALREADY_CHECKEDOUT); } - // Make sure we are no checking out a working copy node + // Make sure we are not checking out a working copy node if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY)) { throw new CheckOutCheckInServiceException(MSG_ERR_ALREADY_WORKING_COPY); @@ -400,10 +400,6 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService // Invoke before check out policy invokeBeforeCheckOut(nodeRef, destinationParentNodeRef, destinationAssocTypeQName, destinationAssocQName); - - // Rename the working copy - String copyName = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); - copyName = createWorkingCopyName(copyName); // Get the user final String userName = getUserName(); @@ -411,7 +407,12 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService NodeRef workingCopy = null; ruleService.disableRuleType(RuleType.UPDATE); try - { + { + // Rename the working copy + String copyName = (String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); + String workingCopyLabel = getWorkingCopyLabel(); + copyName = createWorkingCopyName(copyName, workingCopyLabel); + // Make the working copy final QName copyQName = QName.createQName(destinationAssocQName.getNamespaceURI(), QName.createValidLocalName(copyName)); @@ -455,6 +456,7 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService // Apply the working copy aspect to the working copy Map workingCopyProperties = new HashMap(1); workingCopyProperties.put(ContentModel.PROP_WORKING_COPY_OWNER, userName); + workingCopyProperties.put(ContentModel.PROP_WORKING_COPY_LABEL, workingCopyLabel); nodeService.addAspect(workingCopy, ContentModel.ASPECT_WORKING_COPY, workingCopyProperties); nodeService.addAspect(nodeRef, ContentModel.ASPECT_CHECKED_OUT, null); nodeService.createAssociation(nodeRef, workingCopy, ContentModel.ASSOC_WORKING_COPY_LINK); @@ -572,36 +574,43 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService { String origName = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); String name = (String)nodeService.getProperty(workingCopyNodeRef, ContentModel.PROP_NAME); - if (hasWorkingCopyNameChanged(name, origName)) + String wcLabel = (String)this.nodeService.getProperty(workingCopyNodeRef, ContentModel.PROP_WORKING_COPY_LABEL); + if (wcLabel == null) + { + wcLabel = getWorkingCopyLabel(); + } + + if (hasWorkingCopyNameChanged(name, origName, wcLabel)) { // ensure working copy has working copy label in its name to avoid name clash - if (!name.contains(" " + getWorkingCopyLabel())) + if (!name.contains(" " + wcLabel)) { try { - fileFolderService.rename(workingCopyNodeRef, createWorkingCopyName(name)); + fileFolderService.rename(workingCopyNodeRef, createWorkingCopyName(name, wcLabel)); } catch (FileExistsException e) { - throw new CheckOutCheckInServiceException(e, MSG_ERR_CANNOT_RENAME, name, createWorkingCopyName(name)); + throw new CheckOutCheckInServiceException(e, MSG_ERR_CANNOT_RENAME, name, wcLabel); } catch (FileNotFoundException e) { - throw new CheckOutCheckInServiceException(e, MSG_ERR_CANNOT_RENAME, name, createWorkingCopyName(name)); + throw new CheckOutCheckInServiceException(e, MSG_ERR_CANNOT_RENAME, name, wcLabel); } } + String newName = getNameFromWorkingCopyName(name, wcLabel); try { // rename original to changed working name - fileFolderService.rename(nodeRef, getNameFromWorkingCopyName(name)); + fileFolderService.rename(nodeRef, newName); } catch (FileExistsException e) { - throw new CheckOutCheckInServiceException(e, MSG_ERR_CANNOT_RENAME, origName, getNameFromWorkingCopyName(name)); + throw new CheckOutCheckInServiceException(e, MSG_ERR_CANNOT_RENAME, origName, newName); } catch (FileNotFoundException e) { - throw new CheckOutCheckInServiceException(e, MSG_ERR_CANNOT_RENAME, name, getNameFromWorkingCopyName(name)); + throw new CheckOutCheckInServiceException(e, MSG_ERR_CANNOT_RENAME, name, newName); } } } @@ -745,14 +754,25 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService } /** - * Create working copy name + * Create a working copy name using the given fileName and workingCopyLabel. The label will be inserted before + * the file extension (if present), or else appended to the name (in either case a space is prepended to the + * workingCopyLabel). + *

+ * Examples, where workingCopyLabel is "wc": + *

+ * "Myfile.txt" becomes "Myfile wc.txt", "Myfile" becomes "Myfile wc". + *

+ * In the event that fileName is empty or null, the workingCopyLabel is used for the new working copy name + *

+ * Example: "" becomes "wc". * - * @param name name - * @return working copy name + * @param name + * @param workingCopyLabel + * @return */ - public static String createWorkingCopyName(String name) + public static String createWorkingCopyName(String name, final String workingCopyLabel) { - if (getWorkingCopyLabel() != null && getWorkingCopyLabel().length() != 0) + if (workingCopyLabel != null && workingCopyLabel.length() != 0) { if (name != null && name.length() != 0) { @@ -760,30 +780,31 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService if (index > 0) { // Insert the working copy label before the file extension - name = name.substring(0, index) + " " + getWorkingCopyLabel() + name.substring(index); + name = name.substring(0, index) + " " + workingCopyLabel + name.substring(index); } else { // Simply append the working copy label onto the end of the existing name - name = name + " " + getWorkingCopyLabel(); + name = name + " " + workingCopyLabel; } } else { - name = getWorkingCopyLabel(); + name = workingCopyLabel; } } return name; } /** - * Get original name from working copy name + * Get original name from the working copy name and the cm:workingCopyLabel + * that was used to create it. * + * @param workingCopyLabel * @return original name */ - private String getNameFromWorkingCopyName(String workingCopyName) + private String getNameFromWorkingCopyName(String workingCopyName, String workingCopyLabel) { - String workingCopyLabel = getWorkingCopyLabel(); String workingCopyLabelRegEx = workingCopyLabel.replaceAll("\\(", "\\\\("); workingCopyLabelRegEx = workingCopyLabelRegEx.replaceAll("\\)", "\\\\)"); if (workingCopyName.contains(" " + workingCopyLabel)) @@ -800,13 +821,15 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService /** * Has the working copy name changed compared to the original name * - * @param name working copy name + * @param workingCopyName working copy name * @param origName original name + * @param wcLabel that was inserted into origName to create the original working copy name * @return true => if changed */ - private boolean hasWorkingCopyNameChanged(String workingCopyName, String origName) + private boolean hasWorkingCopyNameChanged(String workingCopyName, String origName, String wcLabel) { - return !workingCopyName.equals(createWorkingCopyName(origName)); + String origWorkingCopyName = createWorkingCopyName(origName, wcLabel); + return !workingCopyName.equals(origWorkingCopyName); } /** diff --git a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImplTest.java b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImplTest.java index b1301fd7de..5823d1fa63 100644 --- a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImplTest.java +++ b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImplTest.java @@ -22,6 +22,7 @@ import java.io.Serializable; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import org.alfresco.model.ContentModel; @@ -53,6 +54,7 @@ import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.BaseSpringTest; import org.alfresco.util.GUID; import org.alfresco.util.TestWithUserUtils; +import org.springframework.extensions.surf.util.I18NUtil; /** * Version operations service implementation unit tests @@ -218,12 +220,20 @@ public class CheckOutCheckInServiceImplTest extends BaseSpringTest // Check that the working copy owner has been set correctly assertEquals(this.userNodeRef, nodeService.getProperty(workingCopy, ContentModel.PROP_WORKING_COPY_OWNER)); + // Check that the working copy name has been set correctly - String name = (String)nodeService.getProperty(this.nodeRef, PROP_NAME_QNAME); - String workingCopyLabel = CheckOutCheckInServiceImpl.createWorkingCopyName(name); - String workingCopyName = (String)nodeService.getProperty(workingCopy, PROP_NAME_QNAME); - assertEquals(workingCopyLabel, workingCopyName); + String name = (String)this.nodeService.getProperty(this.nodeRef, PROP_NAME_QNAME); + String expectedWorkingCopyLabel = I18NUtil.getMessage("coci_service.working_copy_label"); + String expectedWorkingCopyName = + ((CheckOutCheckInServiceImpl)this.cociService).createWorkingCopyName(name, expectedWorkingCopyLabel); + String workingCopyName = (String)this.nodeService.getProperty(workingCopy, PROP_NAME_QNAME); + assertEquals(expectedWorkingCopyName, workingCopyName); + // Check a record has been kept of the working copy label used to create the working copy name + assertEquals( + "No record of working copy label kept", + expectedWorkingCopyLabel, + nodeService.getProperty(workingCopy, ContentModel.PROP_WORKING_COPY_LABEL)); // Ensure that the content has been copied correctly ContentReader contentReader = this.contentService.getReader(this.nodeRef, ContentModel.PROP_CONTENT); @@ -298,10 +308,63 @@ public class CheckOutCheckInServiceImplTest extends BaseSpringTest NodeRef workingCopy2 = checkout(); Map versionProperties2 = new HashMap(); versionProperties2.put(Version.PROP_DESCRIPTION, "Another version test"); - cociService.checkin(workingCopy2, versionProperties2, null, true); - cociService.checkin(workingCopy2, new HashMap(), null, true); + this.cociService.checkin(workingCopy2, versionProperties2, null, true); + this.cociService.checkin(workingCopy2, new HashMap(), null, true); } + public void testCheckOutCheckInWithDifferentLocales() + { + // Check-out nodeRef using the locale fr_FR + Locale.setDefault(Locale.FRANCE); + NodeRef workingCopy = this.cociService.checkout( + this.nodeRef, + this.rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName("workingCopy")); + assertNotNull(workingCopy); + + // Check that the working copy name has been set correctly + String workingCopyName = (String) nodeService.getProperty(workingCopy, PROP_NAME_QNAME); + assertEquals("Working copy name not correct", "myDocument (Copie de Travail).doc", workingCopyName); + + // Check-in using the locale en_GB + Locale.setDefault(Locale.UK); + Map versionProperties = new HashMap(); + versionProperties.put(Version.PROP_DESCRIPTION, "This is a test version"); + cociService.checkin(workingCopy, versionProperties); + + String name = (String) nodeService.getProperty(nodeRef, PROP_NAME_QNAME); + assertEquals("Working copy label was not removed.", "myDocument.doc", name); + } + + public void testCheckOutCheckInWithAlteredWorkingCopyName() + { + // Check-out nodeRef using the locale fr_FR + Locale.setDefault(Locale.FRANCE); + NodeRef workingCopy = this.cociService.checkout( + this.nodeRef, + this.rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName("workingCopy")); + assertNotNull(workingCopy); + + // Check that the working copy name has been set correctly + String workingCopyName = (String) nodeService.getProperty(workingCopy, PROP_NAME_QNAME); + assertEquals("Working copy name not correct", "myDocument (Copie de Travail).doc", workingCopyName); + + // Alter the working copy name + nodeService.setProperty(workingCopy, PROP_NAME_QNAME, "newName (Copie de Travail).doc"); + + // Check-in using the locale en_GB + Locale.setDefault(Locale.UK); + Map versionProperties = new HashMap(); + versionProperties.put(Version.PROP_DESCRIPTION, "This is a test version"); + cociService.checkin(workingCopy, versionProperties); + + String name = (String) nodeService.getProperty(nodeRef, PROP_NAME_QNAME); + assertEquals("File not renamed correctly.", "newName.doc", name); + } + public void testCheckInWithNameChange() { // Check out the file diff --git a/source/java/org/alfresco/repo/imap/ImapMessageTest.java b/source/java/org/alfresco/repo/imap/ImapMessageTest.java index a2541b2d3c..813cb809b4 100644 --- a/source/java/org/alfresco/repo/imap/ImapMessageTest.java +++ b/source/java/org/alfresco/repo/imap/ImapMessageTest.java @@ -205,7 +205,7 @@ public class ImapMessageTest extends TestCase // Starting IMAP - imapServiceImpl.startup(); + imapServiceImpl.startupInTxn(); nodeRefs = searchService.selectNodes(storeRootNodeRef, companyHomePathInStore + "/" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + IMAP_FOLDER_NAME, null, namespaceService, false); diff --git a/source/java/org/alfresco/repo/imap/ImapServiceImpl.java b/source/java/org/alfresco/repo/imap/ImapServiceImpl.java index 2cf79f3e6a..982ebe38f4 100644 --- a/source/java/org/alfresco/repo/imap/ImapServiceImpl.java +++ b/source/java/org/alfresco/repo/imap/ImapServiceImpl.java @@ -204,27 +204,24 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol @Override protected void onBootstrap(ApplicationEvent event) { - service.serviceRegistry.getTransactionService().getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - if (service.getImapServerEnabled()) - { - service.startup(); - } - return null; - } - }); + service.startupInTxn(); } @Override protected void onShutdown(ApplicationEvent event) { - if (service.getImapServerEnabled()) + AuthenticationUtil.runAs(new RunAsWork() { - service.shutdown(); - } + @Override + public Void doWork() throws Exception + { + if (service.getImapServerEnabled()) + { + service.shutdown(); + } + return null; + } + }, AuthenticationUtil.getSystemUserName()); } } @@ -390,6 +387,9 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol } } + /** + * This method is run as System within a single transaction on startup. + */ public void startup() { bindBehaviour(); @@ -398,61 +398,62 @@ public class ImapServiceImpl implements ImapService, OnCreateChildAssociationPol final SearchService searchService = serviceRegistry.getSearchService(); // Get NodeRefs for folders to ignore - this.ignoreExtractionFolders = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork>() + this.ignoreExtractionFolders = new HashSet(ignoreExtractionFoldersBeans.length * 2); + + for (RepositoryFolderConfigBean ignoreExtractionFoldersBean : ignoreExtractionFoldersBeans) { - public Set doWork() throws Exception + NodeRef nodeRef = ignoreExtractionFoldersBean.getFolderPath(namespaceService, nodeService, searchService, + fileFolderService); + + if (!ignoreExtractionFolders.add(nodeRef)) { - Set result = new HashSet(ignoreExtractionFoldersBeans.length * 2); - - for (RepositoryFolderConfigBean ignoreExtractionFoldersBean : ignoreExtractionFoldersBeans) - { - NodeRef nodeRef = ignoreExtractionFoldersBean.getFolderPath( - namespaceService, nodeService, searchService, fileFolderService); - - if (!result.add(nodeRef)) - { - // It was already in the set - throw new AlfrescoRuntimeException( - "The folder extraction path has been referenced already: \n" + - " Folder: " + ignoreExtractionFoldersBean); - } - } - - return result; + // It was already in the set + throw new AlfrescoRuntimeException("The folder extraction path has been referenced already: \n" + + " Folder: " + ignoreExtractionFoldersBean); } - }, AuthenticationUtil.getSystemUserName()); + } // Locate or create IMAP home - imapHomeNodeRef = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() - { - public NodeRef doWork() throws Exception - { - return imapHomeConfigBean.getOrCreateFolderPath(namespaceService, nodeService, searchService, fileFolderService); - } - }, AuthenticationUtil.getSystemUserName()); + imapHomeNodeRef = imapHomeConfigBean.getOrCreateFolderPath(namespaceService, nodeService, searchService, fileFolderService); // Hit the mount points and warm the caches for early failure - AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + for (String mountPointName : imapConfigMountPoints.keySet()) { - public Void doWork() throws Exception + for (AlfrescoImapFolder mailbox : listMailboxes(new AlfrescoImapUser(null, AuthenticationUtil + .getSystemUserName(), null), mountPointName + "*", false)) { - for (String mountPointName: imapConfigMountPoints.keySet()) - { - for (AlfrescoImapFolder mailbox : listMailboxes(new AlfrescoImapUser(null, AuthenticationUtil - .getSystemUserName(), null), mountPointName + "*", false)) - { - mailbox.getUidNext(); - } - } - return null; + mailbox.getUidNext(); } - }, AuthenticationUtil.getSystemUserName()); - + } } public void shutdown() { } + + protected void startupInTxn() + { + if (getImapServerEnabled()) + { + AuthenticationUtil.runAs(new RunAsWork() + { + @Override + public Void doWork() throws Exception + { + return serviceRegistry.getTransactionService().getRetryingTransactionHelper().doInTransaction( + new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + startup(); + return null; + } + }); + } + }, AuthenticationUtil.getSystemUserName()); + } + } protected void bindBehaviour() { diff --git a/source/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java b/source/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java index 5bcf42cbbb..fada432d22 100644 --- a/source/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java +++ b/source/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java @@ -10,7 +10,6 @@ import junit.framework.TestCase; import org.alfresco.model.ContentModel; import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory; import org.alfresco.repo.model.filefolder.FileFolderServiceImpl; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; @@ -99,15 +98,7 @@ public class ImapServiceImplCacheTest extends TestCase imapServiceImpl.setImapHome(imapHome); // Starting IMAP - transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - imapServiceImpl.startup(); - return null; - } - }); + imapServiceImpl.startupInTxn(); nodeRefs = searchService.selectNodes(storeRootNodeRef, companyHomePathInStore + "/" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + TEST_IMAP_FOLDER_NAME, diff --git a/source/java/org/alfresco/repo/imap/ImapServiceImplTest.java b/source/java/org/alfresco/repo/imap/ImapServiceImplTest.java index e0c4369141..1921d511ae 100644 --- a/source/java/org/alfresco/repo/imap/ImapServiceImplTest.java +++ b/source/java/org/alfresco/repo/imap/ImapServiceImplTest.java @@ -180,7 +180,7 @@ public class ImapServiceImplTest extends TestCase imapServiceImpl.setImapHome(imapHome); // Starting IMAP - imapServiceImpl.startup(); + imapServiceImpl.startupInTxn(); nodeRefs = searchService.selectNodes(storeRootNodeRef, companyHomePathInStore + "/" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + TEST_IMAP_FOLDER_NAME, diff --git a/source/java/org/alfresco/repo/imap/LoadTester.java b/source/java/org/alfresco/repo/imap/LoadTester.java index eda81042d5..9aec62b9fd 100644 --- a/source/java/org/alfresco/repo/imap/LoadTester.java +++ b/source/java/org/alfresco/repo/imap/LoadTester.java @@ -163,7 +163,7 @@ public class LoadTester extends TestCase imapServiceImpl.setImapHome(imapHome); // Starting IMAP - imapServiceImpl.startup(); + imapServiceImpl.startupInTxn(); nodeRefs = searchService.selectNodes(storeRootNodeRef, companyHomePathInStore + "/" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + TEST_IMAP_ROOT_FOLDER_NAME, diff --git a/source/java/org/alfresco/repo/jscript/ScriptUtils.java b/source/java/org/alfresco/repo/jscript/ScriptUtils.java index 569beeef34..ad771d9374 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptUtils.java +++ b/source/java/org/alfresco/repo/jscript/ScriptUtils.java @@ -282,9 +282,10 @@ public final class ScriptUtils extends BaseScopableProcessorExtension /** * Sets current Locale from string */ - public void setLocale(String language) + public void setLocale(String localeStr) { - I18NUtil.setLocale(new Locale(language)); + Locale newLocale = I18NUtil.parseLocale(localeStr); + I18NUtil.setLocale(newLocale); } /** diff --git a/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextFactory.java b/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextFactory.java index 710f2d583b..5fb70ae720 100644 --- a/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextFactory.java +++ b/source/java/org/alfresco/repo/management/subsystems/ChildApplicationContextFactory.java @@ -417,6 +417,7 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer(); configurer.setProperties(properties); configurer.setIgnoreUnresolvablePlaceholders(true); + configurer.setSearchSystemEnvironment(false); addBeanFactoryPostProcessor(configurer); // Add all the post processors of the parent, e.g. to make sure system placeholders get expanded properly diff --git a/source/java/org/alfresco/repo/node/FullNodeServiceTest.java b/source/java/org/alfresco/repo/node/FullNodeServiceTest.java index 9d63b9e96c..950b9f262a 100644 --- a/source/java/org/alfresco/repo/node/FullNodeServiceTest.java +++ b/source/java/org/alfresco/repo/node/FullNodeServiceTest.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -56,6 +57,8 @@ public class FullNodeServiceTest extends BaseNodeServiceTest protected void onSetUpInTransaction() throws Exception { super.onSetUpInTransaction(); + Locale.setDefault(Locale.ENGLISH); + MLPropertyInterceptor.setMLAware(false); } public void testMLTextValues() throws Exception @@ -73,7 +76,7 @@ public class FullNodeServiceTest extends BaseNodeServiceTest BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE, mlTextProperty); - // Check filterered property retrieval + // Check filtered property retrieval Serializable textValueFiltered = nodeService.getProperty( rootNodeRef, BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE); @@ -90,6 +93,139 @@ public class FullNodeServiceTest extends BaseNodeServiceTest propertiesFiltered.get(BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE)); } + /** + * ALF-3756 - original fix didn't cope with existing MLText properties having one or more variants + * of a particular language. Upgrading to the fix would therefore not solve the problem properly. + *

+ * For example, if a property has en_GB text in it, then 'updating' that property + * with a locale of en_US will result in the addition of the en_US text rather than a true update (they're both + * English, and using two slightly differently configured browsers in this way leads to confusion). + */ + public void testMLTextUpdatedForCorrectLanguage() throws Exception + { + Locale.setDefault(Locale.UK); + MLPropertyInterceptor.setMLAware(true); + MLText mlTextProperty = new MLText(); + mlTextProperty.addValue(Locale.UK, "en_GB String"); + mlTextProperty.addValue(Locale.FRANCE, "fr_FR String"); + + // Store the MLText property + nodeService.setProperty( + rootNodeRef, + BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE, + mlTextProperty); + + // Pre-test check that an MLText property has been created with the correct locale/text pairs. + Serializable textValue = nodeService.getProperty( + rootNodeRef, + BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE); + assertEquals(2, ((MLText) textValue).size()); + assertEquals("en_GB String", ((MLText) textValue).getValue(Locale.UK)); + assertEquals("fr_FR String", ((MLText) textValue).getValue(Locale.FRANCE)); + + // Enable MLText filtering - as this is how the repo will be used. + MLPropertyInterceptor.setMLAware(false); + + // Retrieve the MLText - but it is filtered into an appropriate String + textValue = nodeService.getProperty( + rootNodeRef, + BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE); + assertEquals("en_GB String", (String) textValue); + + // Update the property, only this time using a different English variant + Locale.setDefault(Locale.US); // en_US + nodeService.setProperty( + rootNodeRef, + BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE, + "Not using MLText for this part."); + + // Check that the text was updated rather than added to + MLPropertyInterceptor.setMLAware(true); // no filtering - see real MLText + // Check that there are not too many English strings, we don't want one for en_GB and one for en_US + textValue = nodeService.getProperty( + rootNodeRef, + BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE); + assertEquals(2, ((MLText) textValue).size()); + assertEquals("Text wasn't updated correctly", + "Not using MLText for this part.", + ((MLText) textValue).getValue(Locale.ENGLISH)); + assertEquals("Failed to get text using locale it was added with", + "Not using MLText for this part.", + ((MLText) textValue).getClosestValue(Locale.US)); + assertEquals("Failed to get text using original locale", + "Not using MLText for this part.", + ((MLText) textValue).getClosestValue(Locale.UK)); + assertEquals("fr_FR String", ((MLText) textValue).getValue(Locale.FRANCE)); + } + + @SuppressWarnings("unchecked") + public void testMLTextCollectionUpdatedForCorrectLanguage() + { + Locale.setDefault(Locale.UK); + MLPropertyInterceptor.setMLAware(true); + + ArrayList values = new ArrayList(); + values.add(new MLText(Locale.UK, "en_GB text")); + values.add(new MLText(Locale.US, "en_US text")); + values.add(new MLText(Locale.FRANCE, "fr_FR text")); + + // Set the property with no MLText filtering + nodeService.setProperty(rootNodeRef, PROP_QNAME_MULTI_ML_VALUE, values); + + // Pre-test check + List checkValues = (List) nodeService.getProperty( + rootNodeRef, PROP_QNAME_MULTI_ML_VALUE); + assertEquals("Expected 3 MLText values back", 3, checkValues.size()); + assertEquals("en_GB text", ((MLText) checkValues.get(0)).getValue(Locale.UK)); + assertEquals("en_US text", ((MLText) checkValues.get(1)).getValue(Locale.US)); + assertEquals("fr_FR text", ((MLText) checkValues.get(2)).getValue(Locale.FRANCE)); + + // Enable MLText filtering - as this is how the repo will be used. + MLPropertyInterceptor.setMLAware(false); + + // Filtering will result in a list containing en_GB only + checkValues = (List) nodeService.getProperty( + rootNodeRef, + PROP_QNAME_MULTI_ML_VALUE); + assertEquals("Expected 1 MLText values back", 1, checkValues.size()); + assertEquals("en_GB text", (String) checkValues.get(0)); + + // Update the property, only this time using a different English variant + Locale.setDefault(Locale.US); // en_US + + values.clear(); + values.add("text 1 added using en_US"); + values.add("text 2 added using en_US"); + values.add("text 3 added using en_US"); + values.add("text 4 added using en_US"); + nodeService.setProperty(rootNodeRef, PROP_QNAME_MULTI_ML_VALUE, values); + + // Check that the text was updated correctly + MLPropertyInterceptor.setMLAware(true); // no filtering - see real MLText + checkValues = (List) nodeService.getProperty( + rootNodeRef, + PROP_QNAME_MULTI_ML_VALUE); + + assertEquals("Expected 3 MLText values back", 4, checkValues.size()); + + MLText mlText = ((MLText) checkValues.get(0)); + assertEquals("en_GB should be replaced with new, not added to", 1, mlText.size()); + assertEquals("text 1 added using en_US", mlText.getValue(Locale.ENGLISH)); + + mlText = ((MLText) checkValues.get(1)); + assertEquals("en_US should be replaced with new, not added to", 1, mlText.size()); + assertEquals("text 2 added using en_US", mlText.getValue(Locale.ENGLISH)); + + mlText = ((MLText) checkValues.get(2)); + assertEquals("en_US should be added to fr_FR", 2, mlText.size()); + assertEquals("fr_FR text", mlText.getValue(Locale.FRANCE)); + assertEquals("text 3 added using en_US", mlText.getValue(Locale.ENGLISH)); + + mlText = ((MLText) checkValues.get(3)); + assertEquals("entirely new text value should be added", 1, mlText.size()); + assertEquals("text 4 added using en_US", mlText.getValue(Locale.ENGLISH)); + } + public void testLongMLTextValues() throws Exception { StringBuilder sb = new StringBuilder(); diff --git a/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java b/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java index f0c6928942..4795bd4e1e 100644 --- a/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java +++ b/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.Locale; import java.util.Map; @@ -551,7 +552,7 @@ public class MLPropertyInterceptor implements MethodInterceptor { newMLValue = new MLText(); } - newMLValue.addValue(contentLocale, current); + replaceTextForLanguage(contentLocale, current, newMLValue); if(count < returnMLList.size()) { returnMLList.set(count, newMLValue); @@ -602,8 +603,8 @@ public class MLPropertyInterceptor implements MethodInterceptor } // Force the inbound value to be a String (it isn't MLText) String inboundValueStr = DefaultTypeConverter.INSTANCE.convert(String.class, inboundValue); - // Add it to the current MLValue - returnMLValue.put(contentLocale, inboundValueStr); + // Update the text for the appropriate language. + replaceTextForLanguage(contentLocale, inboundValueStr, returnMLValue); // Done ret = returnMLValue; } @@ -641,4 +642,32 @@ public class MLPropertyInterceptor implements MethodInterceptor } return ret; } + + /** + * Replace any text in mlText having the same language (but any variant) as contentLocale + * with updatedText keyed by the language of contentLocale. This ensures that the mlText + * will have no more than one entry for the particular language. + * + * @param contentLocale + * @param updatedText + * @param mlText + */ + private void replaceTextForLanguage(Locale contentLocale, String updatedText, MLText mlText) + { + String language = contentLocale.getLanguage(); + // Remove all text entries having the same language as the chosen contentLocale + // (e.g. if contentLocale is en_GB, then remove text for en, en_GB, en_US etc. + Iterator locales = mlText.getLocales().iterator(); + while (locales.hasNext()) + { + Locale locale = locales.next(); + if (locale.getLanguage().equals(language)) + { + locales.remove(); + } + } + + // Add the new value for the specific language + mlText.addValue(new Locale(language), updatedText); + } } diff --git a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java index 22a7832bb9..b6bd092622 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java @@ -1767,6 +1767,50 @@ public class RuleServiceCoverageTest extends TestCase }); } + public void testAssociationUpdateRule() + { + //ALF-9661 test + NodeRef sourceFolder = this.nodeService.createNode( + this.rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName("{test}sourceFolder"), + ContentModel.TYPE_FOLDER).getChildRef(); + Map params = new HashMap(1); + params.put("aspect-name", ContentModel.ASPECT_VERSIONABLE); + //create a rule that adds an aspect after a property is updated + Rule rule = createRule( + RuleType.UPDATE, + AddFeaturesActionExecuter.NAME, + params, + NoConditionEvaluator.NAME, + null); + + this.ruleService.saveRule(sourceFolder, rule); + //create folders + NodeRef testNodeOneRef = this.nodeService.createNode( + sourceFolder, + ContentModel.ASSOC_CONTAINS, + QName.createQName(TEST_NAMESPACE, "original1"), + ContentModel.TYPE_CONTENT, + getContentProperties()).getChildRef(); + addContentToNode(testNodeOneRef); + + NodeRef testNodeTwoRef = this.nodeService.createNode( + sourceFolder, + ContentModel.ASSOC_CONTAINS, + QName.createQName(TEST_NAMESPACE, "original2"), + ContentModel.TYPE_CONTENT, + getContentProperties()).getChildRef(); + addContentToNode(testNodeTwoRef); + //there is no aspect + assertFalse(this.nodeService.hasAspect(testNodeOneRef, ContentModel.ASPECT_VERSIONABLE)); + //create an association + this.nodeService.addAspect(testNodeOneRef, ContentModel.ASPECT_REFERENCING, null); + this.nodeService.createAssociation(testNodeOneRef, testNodeTwoRef, ContentModel.ASSOC_REFERENCES); + //there should be the versionable aspect added + assertTrue(this.nodeService.hasAspect(testNodeOneRef, ContentModel.ASPECT_VERSIONABLE)); + } + /** * Test: * rule type: outbound diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/SingleAssocRefPolicyRuleTrigger.java b/source/java/org/alfresco/repo/rule/ruletrigger/SingleAssocRefPolicyRuleTrigger.java index b020d412b7..4273268519 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/SingleAssocRefPolicyRuleTrigger.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/SingleAssocRefPolicyRuleTrigger.java @@ -18,18 +18,23 @@ */ package org.alfresco.repo.rule.ruletrigger; +import java.util.List; + import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.service.cmr.repository.AssociationRef; -import org.alfresco.service.cmr.rule.RuleServiceException; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.alfresco.util.PropertyCheck; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; public class SingleAssocRefPolicyRuleTrigger extends RuleTriggerAbstractBase { - private static final String ERR_POLICY_NAME_NOT_SET = "Unable to register rule trigger since policy name has not been set."; - + private static Log logger = LogFactory.getLog(OnPropertyUpdateRuleTrigger.class); + private String policyNamespace = NamespaceService.ALFRESCO_URI; - private String policyName; public void setPolicyNamespace(String policyNamespace) @@ -47,10 +52,8 @@ public class SingleAssocRefPolicyRuleTrigger extends RuleTriggerAbstractBase */ public void registerRuleTrigger() { - if (policyName == null) - { - throw new RuleServiceException(ERR_POLICY_NAME_NOT_SET); - } + PropertyCheck.mandatory(this, "policyNamespace", policyNamespace); + PropertyCheck.mandatory(this, "policyName", policyName); this.policyComponent.bindAssociationBehaviour( QName.createQName(this.policyNamespace, this.policyName), @@ -58,8 +61,19 @@ public class SingleAssocRefPolicyRuleTrigger extends RuleTriggerAbstractBase new JavaBehaviour(this, "policyBehaviour")); } - public void policyBehaviour(AssociationRef assocRef) - { - triggerRules(assocRef.getSourceRef(), assocRef.getTargetRef()); - } + public void policyBehaviour(AssociationRef assocRef) + { + NodeRef nodeRef = assocRef.getSourceRef(); + List parentsAssocRefs = this.nodeService.getParentAssocs(nodeRef); + for (ChildAssociationRef parentAssocRef : parentsAssocRefs) + { + triggerRules(parentAssocRef.getParentRef(), nodeRef); + if (logger.isDebugEnabled() == true) + { + logger.debug( + "OnUpdateAssoc rule triggered (parent); " + + "nodeRef=" + parentAssocRef.getParentRef()); + } + } + } } diff --git a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java index f0b46e18e1..bce6076ba1 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java @@ -32,8 +32,8 @@ import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; import java.nio.channels.FileChannel.MapMode; +import java.nio.channels.FileLock; import java.util.ArrayList; import java.util.Collections; import java.util.EnumMap; @@ -74,16 +74,15 @@ import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.CorruptIndexException; -import org.apache.lucene.index.FilterIndexReader; import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexReader.FieldOption; import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.IndexWriter.MaxFieldLength; import org.apache.lucene.index.LogDocMergePolicy; import org.apache.lucene.index.MultiReader; import org.apache.lucene.index.SerialMergeScheduler; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermEnum; -import org.apache.lucene.index.IndexReader.FieldOption; -import org.apache.lucene.index.IndexWriter.MaxFieldLength; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; @@ -254,7 +253,7 @@ public class IndexInfo implements IndexMonitor public static final String MAIN_READER = "MainReader"; - private static Timer timer = new Timer(true); + private static Timer timer = new Timer("IndexInfo Cleaner Deamon", true); /** * The logger. diff --git a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java index 5752903fbe..545735c709 100644 --- a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java +++ b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java @@ -642,7 +642,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl private final Map> groupParentAssocsToDelete = new TreeMap>(); private final Map> finalGroupChildAssocs = new TreeMap>(); private List personsProcessed = new LinkedList(); - private Set allZonePersons; + private Set allZonePersons = Collections.emptySet(); private Set deletionCandidates; private long latestTime; @@ -1090,9 +1090,10 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl public void processGroups(UserRegistry userRegistry, boolean allowDeletions, boolean splitTxns) { - // If we got back some groups, we have to cross reference them with the set of known authorities - if (allowDeletions || !this.groupParentAssocsToDelete.isEmpty()) - { + // If we got back some groups, we have to cross reference them with the set of known authorities + if (allowDeletions || !this.groupParentAssocsToCreate.isEmpty() + || !this.personParentAssocsToCreate.isEmpty()) + { final Set allZonePersons = newPersonSet(); final Set allZoneGroups = new TreeSet(); diff --git a/source/java/org/alfresco/repo/site/SiteServiceImpl.java b/source/java/org/alfresco/repo/site/SiteServiceImpl.java index bb778d18e3..3d7e889336 100644 --- a/source/java/org/alfresco/repo/site/SiteServiceImpl.java +++ b/source/java/org/alfresco/repo/site/SiteServiceImpl.java @@ -1461,7 +1461,6 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic // Build an array of name filter tokens pre lowercased to test against person properties // We require that matching people have at least one match against one of these on // either their firstname or last name - // For groups, we require a match against the whole filter on the group name or display name String nameFilterLower = null; String[] nameFilters = new String[0]; if (nameFilter != null && nameFilter.length() != 0) diff --git a/source/java/org/alfresco/repo/usage/ContentUsageImpl.java b/source/java/org/alfresco/repo/usage/ContentUsageImpl.java index 017e7b2fc7..42958dc200 100644 --- a/source/java/org/alfresco/repo/usage/ContentUsageImpl.java +++ b/source/java/org/alfresco/repo/usage/ContentUsageImpl.java @@ -35,6 +35,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.NoSuchPersonException; import org.alfresco.service.cmr.security.OwnableService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.usage.ContentQuotaException; @@ -516,7 +517,14 @@ public class ContentUsageImpl implements ContentUsageService, public long getUserUsage(String userName) { ParameterCheck.mandatoryString("userName", userName); - return getUserUsage(getPerson(userName), false); + + long currentUsage = 0; + NodeRef personNodeRef = getPerson(userName); + if (personNodeRef != null) + { + currentUsage = getUserUsage(personNodeRef, false); + } + return currentUsage; } public long getUserUsage(NodeRef personNodeRef, boolean removeDeltas) @@ -587,7 +595,15 @@ public class ContentUsageImpl implements ContentUsageService, NodeRef personNodeRef = null; try { - personNodeRef = personService.getPerson(userName); + // false to not force user home creation + personNodeRef = personService.getPerson(userName, false); + } + catch (NoSuchPersonException e) + { + // Can get this situation where the person does not exist and may not be created. + // Had to add this catch when not forcing user home folder creation. + // The boolean parameter to getPerson does two things. It should really be split into two booleans. + personNodeRef = null; } catch (RuntimeException e) { diff --git a/source/java/org/alfresco/repo/usage/UsageQuotaProtector.java b/source/java/org/alfresco/repo/usage/UsageQuotaProtector.java index 1d853150db..a3115c79b4 100644 --- a/source/java/org/alfresco/repo/usage/UsageQuotaProtector.java +++ b/source/java/org/alfresco/repo/usage/UsageQuotaProtector.java @@ -92,14 +92,14 @@ public class UsageQuotaProtector implements NodeServicePolicies.OnUpdateProperti Long sizeQuotaAfter = (Long)after.get(ContentModel.PROP_SIZE_QUOTA); // Check for change in sizeCurrent - if ((sizeCurrentBefore != sizeCurrentAfter) && (sizeCurrentBefore != null) && + if ((sizeCurrentBefore != null && !sizeCurrentBefore.equals(sizeCurrentAfter)) && (sizeCurrentBefore != null) && (! (authorityService.hasAdminAuthority() || AuthenticationUtil.isRunAsUserTheSystemUser()))) { throw new AlfrescoRuntimeException("Update failed: protected property 'sizeCurrent'"); } // Check for change in sizeQuota - if ((sizeQuotaBefore != sizeQuotaAfter) && (sizeQuotaBefore != null) && + if ((sizeQuotaBefore != null && !sizeQuotaBefore.equals(sizeQuotaAfter)) && (sizeQuotaBefore != null) && (! (authorityService.hasAdminAuthority() || AuthenticationUtil.isRunAsUserTheSystemUser()))) { throw new AlfrescoRuntimeException("Update failed: protected property 'sizeQuota'"); diff --git a/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java b/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java index 7427300770..bd81c29786 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java @@ -699,7 +699,8 @@ public class WorkflowServiceImpl implements WorkflowService // Expand authorities to include associated groups (and parent groups) List authorities = new ArrayList(); authorities.add(authority); - Set parents = authorityService.getContainingAuthorities(AuthorityType.GROUP, authority, false); + Set parents = authorityService.getContainingAuthoritiesInZone(AuthorityType.GROUP, authority, + null, null, 100); authorities.addAll(parents); // Retrieve pooled tasks for authorities (from each of the registered diff --git a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutorThread.java b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutorThread.java index 9bd874ad52..5913ae8b9f 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutorThread.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJobExecutorThread.java @@ -25,6 +25,8 @@ import java.util.Collections; import java.util.Date; import org.alfresco.repo.lock.LockAcquisitionException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.namespace.NamespaceService; @@ -37,6 +39,7 @@ import org.jbpm.JbpmContext; import org.jbpm.db.JobSession; import org.jbpm.job.Job; import org.jbpm.job.executor.JobExecutorThread; +import org.jbpm.taskmgmt.exe.TaskInstance; /** @@ -170,6 +173,38 @@ public class AlfrescoJobExecutorThread extends JobExecutorThread */ @Override protected void executeJob(final Job jobIn) + { + // execute the job as System (ALF-10776) so transaction commit level + // operations have a security context. + AuthenticationUtil.runAs(new RunAsWork() + { + public Void doWork() throws Exception + { + executeJobImpl(jobIn); + return null; + } + }, getActorId(jobIn)); + + // clear authentication context for this thread + AuthenticationUtil.clearCurrentSecurityContext(); + } + + private String getActorId(final Job jobIn) + { + TaskInstance taskInstance = jobIn.getTaskInstance(); + + if (taskInstance != null) + { + String actorId = taskInstance.getActorId(); + if (actorId != null && actorId.length() > 0) + { + return actorId; + } + } + return AuthenticationUtil.getSystemUserName(); + } + + private void executeJobImpl(final Job jobIn) { if ((!isActive) || (alfrescoJobExecutor.getTransactionService().isReadOnly())) { diff --git a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java index f3e0691c33..72831b45f1 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoTimer.java @@ -18,8 +18,6 @@ */ package org.alfresco.repo.workflow.jbpm; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.jbpm.JbpmContext; import org.jbpm.graph.exe.Token; import org.jbpm.job.Timer; @@ -66,40 +64,21 @@ public class AlfrescoTimer extends Timer { // establish authentication context final TaskInstance taskInstance = getTaskInstance(); - String username = getActorId(taskInstance); // execute timer - return AuthenticationUtil.runAs(new RunAsWork() + boolean deleteTimer = AlfrescoTimer.super.execute(jbpmContext); + + // End the task if timer does not repeat. + // Note the order is a little odd here as the task will be ended + // after the token has been signalled to move to the next node. + if (deleteTimer + && taskInstance != null + && taskInstance.isOpen()) { - public Boolean doWork() throws Exception - { - boolean deleteTimer = AlfrescoTimer.super.execute(jbpmContext); - // End the task if timer does not repeat. - // Note the order is a little odd here as the task will be ended - // after the token has been signalled to move to the next node. - if (deleteTimer - && taskInstance != null - && taskInstance.isOpen()) - { - taskInstance.setSignalling(false); - taskInstance.end(); - } - return deleteTimer; - } - }, username); - } - - private String getActorId(TaskInstance taskInstance) - { - if (taskInstance != null) - { - String actorId = taskInstance.getActorId(); - if (actorId != null && actorId.length() > 0) - { - return actorId; - } + taskInstance.setSignalling(false); + taskInstance.end(); } - return AuthenticationUtil.getSystemUserName(); + + return deleteTimer; } - } diff --git a/source/java/org/alfresco/util/ThreadPoolExecutorFactoryBean.java b/source/java/org/alfresco/util/ThreadPoolExecutorFactoryBean.java index e75d5b43da..f7aa425b16 100644 --- a/source/java/org/alfresco/util/ThreadPoolExecutorFactoryBean.java +++ b/source/java/org/alfresco/util/ThreadPoolExecutorFactoryBean.java @@ -26,6 +26,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.alfresco.error.AlfrescoRuntimeException; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; @@ -57,7 +58,7 @@ import org.springframework.beans.factory.InitializingBean; * * @author Derek Hulley */ -public class ThreadPoolExecutorFactoryBean implements FactoryBean, InitializingBean +public class ThreadPoolExecutorFactoryBean implements FactoryBean, InitializingBean, DisposableBean { 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 @@ -244,4 +245,10 @@ public class ThreadPoolExecutorFactoryBean implements FactoryBean, InitializingB { this.poolName = poolName; } + + public void destroy() + { + this.instance.shutdown(); + } + } diff --git a/source/test-resources/jbpm-test/test-context.xml b/source/test-resources/jbpm-test/test-context.xml index 68e5910710..b2efdbd0e1 100644 --- a/source/test-resources/jbpm-test/test-context.xml +++ b/source/test-resources/jbpm-test/test-context.xml @@ -14,6 +14,9 @@ ${db.url}_test + + false +