diff --git a/config/alfresco/bootstrap/example_javascripts.acp b/config/alfresco/bootstrap/example_javascripts.acp index f954936f08..c079c9152d 100644 Binary files a/config/alfresco/bootstrap/example_javascripts.acp and b/config/alfresco/bootstrap/example_javascripts.acp differ diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml index 57634868a1..b32565a02c 100644 --- a/config/alfresco/content-services-context.xml +++ b/config/alfresco/content-services-context.xml @@ -90,11 +90,7 @@ - - - - - + - - - - - + + + + + + + + diff --git a/config/alfresco/messages/permissions-service.properties b/config/alfresco/messages/permissions-service.properties index 368e3f7c82..3613df7366 100644 --- a/config/alfresco/messages/permissions-service.properties +++ b/config/alfresco/messages/permissions-service.properties @@ -1 +1,2 @@ -permissions.err_access_denied=Access Denied. You do not have the appropriate permissions to perform this operation. +permissions.err_access_denied=Access Denied. You do not have the appropriate permissions to perform this operation. +permissions.err_read_only=Access Denied. The system is currently in read-only mode. \ No newline at end of file diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml index 06ea1289ff..7bb29d5a1a 100644 --- a/config/alfresco/model/contentModel.xml +++ b/config/alfresco/model/contentModel.xml @@ -45,11 +45,6 @@ Folder cm:cmobject true - - - d:boolean - - diff --git a/config/alfresco/model/systemModel.xml b/config/alfresco/model/systemModel.xml index 4a50d06709..80ee14b5d2 100644 --- a/config/alfresco/model/systemModel.xml +++ b/config/alfresco/model/systemModel.xml @@ -127,6 +127,11 @@ Incomplete + + + Temporary + + Archived diff --git a/config/alfresco/templates/content_template_examples.xml b/config/alfresco/templates/content_template_examples.xml index 078bf14ffb..161081c032 100644 --- a/config/alfresco/templates/content_template_examples.xml +++ b/config/alfresco/templates/content_template_examples.xml @@ -2,210 +2,155 @@ - true - admin - 2006-02-10T09:10:45.906Z Displays basic information about the current document - admin contentUrl=classpath:alfresco/templates/content/examples/doc_info.ftl|mimetype=text/plain|size=636|encoding=UTF-8 doc_info.ftl doc_info.ftl - 2005-10-21T15:11:00.446+01:00 - true - admin - 2006-02-10T09:10:50.390Z Calculates if the document has the localizable aspect applied - admin contentUrl=classpath:alfresco/templates/content/examples/localizable.ftl|mimetype=text/plain|size=380|encoding=UTF-8 localizable.ftl localizable.ftl - 2005-10-21T15:11:02.181+01:00 - true - admin - 2006-02-10T09:10:51.937Z Displays a list of the documents in the current user Home Space - admin contentUrl=classpath:alfresco/templates/content/examples/my_docs.ftl|mimetype=text/plain|size=750|encoding=UTF-8 my_docs.ftl my_docs.ftl - 2005-10-21T15:11:03.118+01:00 - true - admin - 2006-02-10T09:10:57.890Z Displays a list of spaces in the current user Home Space - admin contentUrl=classpath:alfresco/templates/content/examples/my_spaces.ftl|mimetype=text/plain|size=682|encoding=UTF-8 my_spaces.ftl my_spaces.ftl - 2005-10-21T15:11:04.665+01:00 - true - admin - 2006-02-10T09:10:59.421Z Shows a simple summary page about the current user and their Home Space - admin contentUrl=classpath:alfresco/templates/content/examples/my_summary.ftl|mimetype=text/plain|size=537|encoding=UTF-8 my_summary.ftl my_summary.ftl - 2005-10-21T15:11:05.509+01:00 - true - admin - 2006-02-10T09:11:04.953Z Calculates if the document has the translatable aspect applied - admin contentUrl=classpath:alfresco/templates/content/examples/translatable.ftl|mimetype=text/plain|size=415|encoding=UTF-8 translatable.ftl translatable.ftl - 2005-10-21T15:11:06.306+01:00 - true - admin - 2006-02-10T09:10:41.656Z Renders a valid RSS2.0 XML document showing the documents in the current space created or modified in the last 7 days. The template should be configured to use the appropriate server and port before use. - admin contentUrl=classpath:alfresco/templates/content/examples/RSS_2.0_recent_docs.ftl|mimetype=text/plain|size=1917|encoding=UTF-8 RSS_2.0_recent_docs.ftl RSS_2.0_recent_docs.ftl - 2006-01-13T15:49:50.695Z - true - admin - 2006-02-10T09:11:00.953Z Displays a list of the documents in the current space created or modified in the last 7 days - admin contentUrl=classpath:alfresco/templates/content/examples/recent_docs.ftl|mimetype=text/plain|size=968|encoding=UTF-8 recent_docs.ftl recent_docs.ftl - 2006-01-13T15:50:02.164Z - true - admin - 2006-02-10T09:10:48.062Z Example of various lists of documents, spaces and summary information about the current user - admin contentUrl=classpath:alfresco/templates/content/examples/general_example.ftl|mimetype=text/plain|size=1608|encoding=UTF-8 general_example.ftl general_example.ftl - 2006-02-10T09:10:47.796Z - true - admin - 2006-02-10T09:10:53.531Z Displays a list of the documents in the current user Home Space. Text document content is shown inline, as is JPG content as small thumbnail images. - admin contentUrl=classpath:alfresco/templates/content/examples/my_docs_inline.ftl|mimetype=text/plain|size=652|encoding=UTF-8 my_docs_inline.ftl my_docs_inline.ftl - 2006-02-10T09:10:53.281Z - true - admin - 2006-02-10T09:11:07.031Z Example of using XPath and Lucene searches within a template. - admin contentUrl=classpath:alfresco/templates/content/examples/xpath_search.ftl|mimetype=text/plain|size=1109|encoding=UTF-8 xpath_search.ftl xpath_search.ftl - 2006-02-10T09:11:06.750Z diff --git a/source/java/org/alfresco/filesys/netbios/server/NetBIOSNameServer.java b/source/java/org/alfresco/filesys/netbios/server/NetBIOSNameServer.java index ae65fe745f..829b18619c 100644 --- a/source/java/org/alfresco/filesys/netbios/server/NetBIOSNameServer.java +++ b/source/java/org/alfresco/filesys/netbios/server/NetBIOSNameServer.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; +import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; import java.util.Hashtable; @@ -1485,6 +1486,54 @@ public class NetBIOSNameServer extends NetworkServer implements Runnable && addrs[i].getHostAddress().equals("0.0.0.0") == false) ipList.add(addrs[i].getAddress()); } + + // Check if the address list is empty, use the network interface list to get the local IP addresses + + if ( ipList.size() == 0) + { + // Enumerate the network adapter list + + Enumeration niEnum = NetworkInterface.getNetworkInterfaces(); + + 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) + ipList.add( curAddr.getAddress()); + } + } + } + + // DEBUG + + if ( ipList.size() > 0 && logger.isDebugEnabled()) + logger.debug("Found " + ipList.size() + " addresses using interface list"); + } + } + else + { + // DBEUG + + if ( logger.isDebugEnabled()) + logger.debug("Found " + ipList.size() + " addresses using host name lookup"); + } // Check if any addresses were added to the list diff --git a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java index 9f62249764..050bee3be8 100644 --- a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java +++ b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java @@ -19,7 +19,9 @@ package org.alfresco.filesys.server.config; 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.security.Provider; import java.security.Security; @@ -811,145 +813,199 @@ public class ServerConfiguration implements ApplicationListener platformOK = true; } - // Check if the broadcast mask has been specified - - if (getBroadcastMask() == null) - throw new AlfrescoRuntimeException("Network broadcast mask not specified"); - // Enable the NetBIOS SMB support, if enabled for this platform setNetBIOSSMB(platformOK); - // Check for a bind address - - String bindto = elem.getAttribute("bindto"); - if (bindto != null && bindto.length() > 0) + // Parse/check NetBIOS settings, if enabled + + if ( hasNetBIOSSMB()) { - - // Validate the bind address - - try - { - - // Check the bind address - - InetAddress bindAddr = InetAddress.getByName(bindto); - - // Set the bind address for the NetBIOS name server - - setNetBIOSBindAddress(bindAddr); - } - catch (UnknownHostException ex) - { - throw new AlfrescoRuntimeException("Invalid NetBIOS bind address"); - } + // Check if the broadcast mask has been specified + + if (getBroadcastMask() == null) + throw new AlfrescoRuntimeException("Network broadcast mask not specified"); + + // Check for a bind address + + String bindto = elem.getAttribute("bindto"); + if (bindto != null && bindto.length() > 0) + { + + // Validate the bind address + + try + { + + // Check the bind address + + InetAddress bindAddr = InetAddress.getByName(bindto); + + // Set the bind address for the NetBIOS name server + + setNetBIOSBindAddress(bindAddr); + } + catch (UnknownHostException ex) + { + throw new AlfrescoRuntimeException("Invalid NetBIOS bind address"); + } + } + else if (hasSMBBindAddress()) + { + + // Use the SMB bind address for the NetBIOS name server + + setNetBIOSBindAddress(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 + + String portNum = elem.getAttribute("sessionPort"); + if ( portNum != null && portNum.length() > 0) { + try { + setNetBIOSSessionPort(Integer.parseInt(portNum)); + if ( getNetBIOSSessionPort() <= 0 || getNetBIOSSessionPort() >= 65535) + throw new AlfrescoRuntimeException("NetBIOS session port out of valid range"); + } + catch (NumberFormatException ex) { + throw new AlfrescoRuntimeException("Invalid NetBIOS session port"); + } + } + + // Check if the name port has been specified + + portNum = elem.getAttribute("namePort"); + if ( portNum != null && portNum.length() > 0) { + try { + setNetBIOSNamePort(Integer.parseInt(portNum)); + if ( getNetBIOSNamePort() <= 0 || getNetBIOSNamePort() >= 65535) + throw new AlfrescoRuntimeException("NetBIOS name port out of valid range"); + } + catch (NumberFormatException ex) { + throw new AlfrescoRuntimeException("Invalid NetBIOS name port"); + } + } + + // Check if the datagram port has been specified + + portNum = elem.getAttribute("datagramPort"); + if ( portNum != null && portNum.length() > 0) { + try { + setNetBIOSDatagramPort(Integer.parseInt(portNum)); + if ( getNetBIOSDatagramPort() <= 0 || getNetBIOSDatagramPort() >= 65535) + throw new AlfrescoRuntimeException("NetBIOS datagram port out of valid range"); + } + catch (NumberFormatException ex) { + throw new AlfrescoRuntimeException("Invalid NetBIOS datagram port"); + } + } } - else if (hasSMBBindAddress()) - { - - // Use the SMB bind address for the NetBIOS name server - - setNetBIOSBindAddress(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) - { - // 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 - - String portNum = elem.getAttribute("sessionPort"); - if ( portNum != null && portNum.length() > 0) { - try { - setNetBIOSSessionPort(Integer.parseInt(portNum)); - if ( getNetBIOSSessionPort() <= 0 || getNetBIOSSessionPort() >= 65535) - throw new AlfrescoRuntimeException("NetBIOS session port out of valid range"); - } - catch (NumberFormatException ex) { - throw new AlfrescoRuntimeException("Invalid NetBIOS session port"); - } - } - - // Check if the name port has been specified - - portNum = elem.getAttribute("namePort"); - if ( portNum != null && portNum.length() > 0) { - try { - setNetBIOSNamePort(Integer.parseInt(portNum)); - if ( getNetBIOSNamePort() <= 0 || getNetBIOSNamePort() >= 65535) - throw new AlfrescoRuntimeException("NetBIOS name port out of valid range"); - } - catch (NumberFormatException ex) { - throw new AlfrescoRuntimeException("Invalid NetBIOS name port"); - } - } - - // Check if the datagram port has been specified - - portNum = elem.getAttribute("datagramPort"); - if ( portNum != null && portNum.length() > 0) { - try { - setNetBIOSDatagramPort(Integer.parseInt(portNum)); - if ( getNetBIOSDatagramPort() <= 0 || getNetBIOSDatagramPort() >= 65535) - throw new AlfrescoRuntimeException("NetBIOS datagram port out of valid range"); - } - catch (NumberFormatException ex) { - throw new AlfrescoRuntimeException("Invalid NetBIOS datagram port"); - } - } } else { diff --git a/source/java/org/alfresco/model/ContentModel.java b/source/java/org/alfresco/model/ContentModel.java index c40491691e..139a5fb8a5 100644 --- a/source/java/org/alfresco/model/ContentModel.java +++ b/source/java/org/alfresco/model/ContentModel.java @@ -40,6 +40,9 @@ public interface ContentModel // tag for incomplete nodes static final QName ASPECT_INCOMPLETE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "incomplete"); + // tag for temporary nodes + static final QName ASPECT_TEMPORARY = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "temporary"); + // archived nodes aspect constants static final QName ASPECT_ARCHIVED = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archived"); static final QName PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedOriginalParentAssoc"); diff --git a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java index ccfb32b96c..ae961e7ca9 100644 --- a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java +++ b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java @@ -46,7 +46,7 @@ import org.alfresco.service.namespace.QName; * * @author Roy Wetherall */ -public class CheckOutCheckInServiceImpl implements CheckOutCheckInService +public class CheckOutCheckInServiceImpl implements CheckOutCheckInService { /** * I18N labels @@ -58,30 +58,30 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService private static final String MSG_ERR_NOT_AUTHENTICATED = "coci_service.err_not_authenticated"; private static final String MSG_ERR_WORKINGCOPY_HAS_NO_MIMETYPE = "coci_service.err_workingcopy_has_no_mimetype"; - /** - * Extension character, used to recalculate the working copy names - */ - private static final String EXTENSION_CHARACTER = "."; - - /** - * The node service - */ - private NodeService nodeService; - - /** - * The version service - */ - private VersionService versionService; - - /** - * The lock service - */ - private LockService lockService; - - /** - * The copy service - */ - private CopyService copyService; + /** + * Extension character, used to recalculate the working copy names + */ + private static final String EXTENSION_CHARACTER = "."; + + /** + * The node service + */ + private NodeService nodeService; + + /** + * The version service + */ + private VersionService versionService; + + /** + * The lock service + */ + private LockService lockService; + + /** + * The copy service + */ + private CopyService copyService; /** * The search service @@ -97,47 +97,47 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService * The versionable aspect behaviour implementation */ private VersionableAspect versionableAspect; - - /** - * Set the node service - * - * @param nodeService the node service - */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - /** - * Set the version service - * - * @param versionService the version service - */ - public void setVersionService(VersionService versionService) - { - this.versionService = versionService; - } - - /** - * Sets the lock service - * - * @param lockService the lock service - */ - public void setLockService(LockService lockService) - { - this.lockService = lockService; - } - - /** + + /** + * Set the node service + * + * @param nodeService the node service + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Set the version service + * + * @param versionService the version service + */ + public void setVersionService(VersionService versionService) + { + this.versionService = versionService; + } + + /** + * Sets the lock service + * + * @param lockService the lock service + */ + public void setLockService(LockService lockService) + { + this.lockService = lockService; + } + + /** * Sets the copy service * * @param copyService the copy service - */ - public void setCopyService( - CopyService copyService) - { - this.copyService = copyService; - } + */ + public void setCopyService( + CopyService copyService) + { + this.copyService = copyService; + } /** * Sets the authentication service @@ -173,57 +173,57 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService /** * Get the working copy label. * - * @return the working copy label + * @return the working copy label */ public String getWorkingCopyLabel() { - return I18NUtil.getMessage(MSG_WORKING_COPY_LABEL); - } - - /** - * @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkout(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName) - */ - public NodeRef checkout( - NodeRef nodeRef, - NodeRef destinationParentNodeRef, - QName destinationAssocTypeQName, - QName destinationAssocQName) - { - // Make sure we are no checking out a working copy node - if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY) == true) - { - throw new CheckOutCheckInServiceException(MSG_ERR_ALREADY_WORKING_COPY); - } - - // Apply the lock aspect if required - if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE) == false) - { - this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_LOCKABLE, null); - } - - // Rename the working copy + return I18NUtil.getMessage(MSG_WORKING_COPY_LABEL); + } + + /** + * @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkout(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName) + */ + public NodeRef checkout( + NodeRef nodeRef, + NodeRef destinationParentNodeRef, + QName destinationAssocTypeQName, + QName destinationAssocQName) + { + // Make sure we are no checking out a working copy node + if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY) == true) + { + throw new CheckOutCheckInServiceException(MSG_ERR_ALREADY_WORKING_COPY); + } + + // Apply the lock aspect if required + if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE) == false) + { + this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_LOCKABLE, null); + } + + // Rename the working copy String copyName = (String)this.nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); - if (this.getWorkingCopyLabel() != null && this.getWorkingCopyLabel().length() != 0) - { - if (copyName != null && copyName.length() != 0) - { - int index = copyName.lastIndexOf(EXTENSION_CHARACTER); - if (index > 0) - { - // Insert the working copy label before the file extension + if (this.getWorkingCopyLabel() != null && this.getWorkingCopyLabel().length() != 0) + { + if (copyName != null && copyName.length() != 0) + { + int index = copyName.lastIndexOf(EXTENSION_CHARACTER); + if (index > 0) + { + // Insert the working copy label before the file extension copyName = copyName.substring(0, index) + " " + getWorkingCopyLabel() + copyName.substring(index); - } - else - { - // Simply append the working copy label onto the end of the existing name + } + else + { + // Simply append the working copy label onto the end of the existing name copyName = copyName + " " + getWorkingCopyLabel(); - } - } + } + } else { copyName = getWorkingCopyLabel(); } - } + } // Make the working copy destinationAssocQName = QName.createQName(destinationAssocQName.getNamespaceURI(), QName.createValidLocalName(copyName)); @@ -236,20 +236,24 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService // Update the working copy name this.nodeService.setProperty(workingCopy, ContentModel.PROP_NAME, copyName); - // Get the user - String userName = getUserName(); - - // Apply the working copy aspect to the working copy - Map workingCopyProperties = new HashMap(1); - workingCopyProperties.put(ContentModel.PROP_WORKING_COPY_OWNER, userName); - this.nodeService.addAspect(workingCopy, ContentModel.ASPECT_WORKING_COPY, workingCopyProperties); - - // Lock the original node - this.lockService.lock(nodeRef, LockType.READ_ONLY_LOCK); - - // Return the working copy - return workingCopy; - } + // Get the user + String userName = getUserName(); + + // Apply the working copy aspect to the working copy + Map workingCopyProperties = new HashMap(1); + workingCopyProperties.put(ContentModel.PROP_WORKING_COPY_OWNER, userName); + this.nodeService.addAspect(workingCopy, ContentModel.ASPECT_WORKING_COPY, workingCopyProperties); + + // Apply the sys:temporary aspect to tag the working copy as a temporary node + // so it doesn't get archived when checked in + this.nodeService.addAspect(workingCopy, ContentModel.ASPECT_TEMPORARY, null); + + // Lock the origional node + this.lockService.lock(nodeRef, LockType.READ_ONLY_LOCK); + + // Return the working copy + return workingCopy; + } /** * Gets the authenticated users node reference @@ -269,64 +273,64 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService } } - /** - * @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkout(org.alfresco.service.cmr.repository.NodeRef) - */ - public NodeRef checkout(NodeRef nodeRef) - { - // Find the primary parent in order to determine where to put the copy - ChildAssociationRef childAssocRef = this.nodeService.getPrimaryParent(nodeRef); - - // Checkout the working copy to the same destination - return checkout(nodeRef, childAssocRef.getParentRef(), childAssocRef.getTypeQName(), childAssocRef.getQName()); - } + /** + * @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkout(org.alfresco.service.cmr.repository.NodeRef) + */ + public NodeRef checkout(NodeRef nodeRef) + { + // Find the primary parent in order to determine where to put the copy + ChildAssociationRef childAssocRef = this.nodeService.getPrimaryParent(nodeRef); + + // Checkout the working copy to the same destination + return checkout(nodeRef, childAssocRef.getParentRef(), childAssocRef.getTypeQName(), childAssocRef.getQName()); + } - /** - * @see org.alfresco.repo.version.operations.VersionOperationsService#checkin(org.alfresco.repo.ref.NodeRef, Map, java.lang.String, boolean) - */ - public NodeRef checkin( - NodeRef workingCopyNodeRef, - Map versionProperties, - String contentUrl, - boolean keepCheckedOut) - { - NodeRef nodeRef = null; - - // Check that we have been handed a working copy - if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_WORKING_COPY) == false) - { - // Error since we have not been passed a working copy - throw new AspectMissingException(ContentModel.ASPECT_WORKING_COPY, workingCopyNodeRef); - } - - // Check that the working node still has the copy aspect applied - if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_COPIEDFROM) == true) - { + /** + * @see org.alfresco.repo.version.operations.VersionOperationsService#checkin(org.alfresco.repo.ref.NodeRef, Map, java.lang.String, boolean) + */ + public NodeRef checkin( + NodeRef workingCopyNodeRef, + Map versionProperties, + String contentUrl, + boolean keepCheckedOut) + { + NodeRef nodeRef = null; + + // Check that we have been handed a working copy + if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_WORKING_COPY) == false) + { + // Error since we have not been passed a working copy + throw new AspectMissingException(ContentModel.ASPECT_WORKING_COPY, workingCopyNodeRef); + } + + // Check that the working node still has the copy aspect applied + if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_COPIEDFROM) == true) + { // Disable versionable behaviours since we don't want the auto version policy behaviour to execute when we check-in this.versionableAspect.disableAutoVersion(); try { Map workingCopyProperties = nodeService.getProperties(workingCopyNodeRef); - // Try and get the original node reference - nodeRef = (NodeRef) workingCopyProperties.get(ContentModel.PROP_COPY_REFERENCE); - if(nodeRef == null) - { - // Error since the original node can not be found - throw new CheckOutCheckInServiceException(MSG_ERR_BAD_COPY); - } - - try - { - // Release the lock - this.lockService.unlock(nodeRef); - } - catch (UnableToReleaseLockException exception) - { - throw new CheckOutCheckInServiceException(MSG_ERR_NOT_OWNER, exception); - } - - if (contentUrl != null) - { + // Try and get the original node reference + nodeRef = (NodeRef) workingCopyProperties.get(ContentModel.PROP_COPY_REFERENCE); + if(nodeRef == null) + { + // Error since the original node can not be found + throw new CheckOutCheckInServiceException(MSG_ERR_BAD_COPY); + } + + try + { + // Release the lock + this.lockService.unlock(nodeRef); + } + catch (UnableToReleaseLockException exception) + { + throw new CheckOutCheckInServiceException(MSG_ERR_NOT_OWNER, exception); + } + + if (contentUrl != null) + { ContentData contentData = (ContentData) workingCopyProperties.get(ContentModel.PROP_CONTENT); if (contentData == null) { @@ -340,15 +344,15 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService contentData.getSize(), contentData.getEncoding()); } - // Set the content url value onto the working copy - this.nodeService.setProperty( - workingCopyNodeRef, - ContentModel.PROP_CONTENT, - contentData); - } + // Set the content url value onto the working copy + this.nodeService.setProperty( + workingCopyNodeRef, + ContentModel.PROP_CONTENT, + contentData); + } - // Copy the contents of the working copy onto the original - this.copyService.copy(workingCopyNodeRef, nodeRef); + // Copy the contents of the working copy onto the original + this.copyService.copy(workingCopyNodeRef, nodeRef); if (versionProperties != null && this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE) == true) { @@ -356,94 +360,94 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService this.versionService.createVersion(nodeRef, versionProperties); } - if (keepCheckedOut == false) - { - // Delete the working copy + if (keepCheckedOut == false) + { + // Delete the working copy this.nodeService.removeAspect(workingCopyNodeRef, ContentModel.ASPECT_WORKING_COPY); - this.nodeService.deleteNode(workingCopyNodeRef); - } - else - { - // Re-lock the original node - this.lockService.lock(nodeRef, LockType.READ_ONLY_LOCK); - } + this.nodeService.deleteNode(workingCopyNodeRef); + } + else + { + // Re-lock the original node + this.lockService.lock(nodeRef, LockType.READ_ONLY_LOCK); + } } finally { this.versionableAspect.enableAutoVersion(); } - - } - else - { - // Error since the copy aspect is missing - throw new AspectMissingException(ContentModel.ASPECT_COPIEDFROM, workingCopyNodeRef); - } - - return nodeRef; - } + + } + else + { + // Error since the copy aspect is missing + throw new AspectMissingException(ContentModel.ASPECT_COPIEDFROM, workingCopyNodeRef); + } + + return nodeRef; + } - /** - * @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkin(org.alfresco.service.cmr.repository.NodeRef, Map, java.lang.String) - */ - public NodeRef checkin( - NodeRef workingCopyNodeRef, - Map versionProperties, - String contentUrl) - { - return checkin(workingCopyNodeRef, versionProperties, contentUrl, false); - } + /** + * @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkin(org.alfresco.service.cmr.repository.NodeRef, Map, java.lang.String) + */ + public NodeRef checkin( + NodeRef workingCopyNodeRef, + Map versionProperties, + String contentUrl) + { + return checkin(workingCopyNodeRef, versionProperties, contentUrl, false); + } - /** - * @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkin(org.alfresco.service.cmr.repository.NodeRef, Map) - */ - public NodeRef checkin( - NodeRef workingCopyNodeRef, - Map versionProperties) - { - return checkin(workingCopyNodeRef, versionProperties, null, false); - } + /** + * @see org.alfresco.service.cmr.coci.CheckOutCheckInService#checkin(org.alfresco.service.cmr.repository.NodeRef, Map) + */ + public NodeRef checkin( + NodeRef workingCopyNodeRef, + Map versionProperties) + { + return checkin(workingCopyNodeRef, versionProperties, null, false); + } - /** - * @see org.alfresco.service.cmr.coci.CheckOutCheckInService#cancelCheckout(org.alfresco.service.cmr.repository.NodeRef) - */ - public NodeRef cancelCheckout(NodeRef workingCopyNodeRef) - { - NodeRef nodeRef = null; - - // Check that we have been handed a working copy - if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_WORKING_COPY) == false) - { - // Error since we have not been passed a working copy - throw new AspectMissingException(ContentModel.ASPECT_WORKING_COPY, workingCopyNodeRef); - } - - // Ensure that the node has the copy aspect - if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_COPIEDFROM) == true) - { - // Get the original node - nodeRef = (NodeRef)this.nodeService.getProperty(workingCopyNodeRef, ContentModel.PROP_COPY_REFERENCE); - if (nodeRef == null) - { - // Error since the original node can not be found - throw new CheckOutCheckInServiceException(MSG_ERR_BAD_COPY); - } - - // Release the lock on the original node - this.lockService.unlock(nodeRef); - - // Delete the working copy + /** + * @see org.alfresco.service.cmr.coci.CheckOutCheckInService#cancelCheckout(org.alfresco.service.cmr.repository.NodeRef) + */ + public NodeRef cancelCheckout(NodeRef workingCopyNodeRef) + { + NodeRef nodeRef = null; + + // Check that we have been handed a working copy + if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_WORKING_COPY) == false) + { + // Error since we have not been passed a working copy + throw new AspectMissingException(ContentModel.ASPECT_WORKING_COPY, workingCopyNodeRef); + } + + // Ensure that the node has the copy aspect + if (this.nodeService.hasAspect(workingCopyNodeRef, ContentModel.ASPECT_COPIEDFROM) == true) + { + // Get the original node + nodeRef = (NodeRef)this.nodeService.getProperty(workingCopyNodeRef, ContentModel.PROP_COPY_REFERENCE); + if (nodeRef == null) + { + // Error since the original node can not be found + throw new CheckOutCheckInServiceException(MSG_ERR_BAD_COPY); + } + + // Release the lock on the original node + this.lockService.unlock(nodeRef); + + // Delete the working copy this.nodeService.removeAspect(workingCopyNodeRef, ContentModel.ASPECT_WORKING_COPY); - this.nodeService.deleteNode(workingCopyNodeRef); - } - else - { - // Error since the copy aspect is missing - throw new AspectMissingException(ContentModel.ASPECT_COPIEDFROM, workingCopyNodeRef); - } - - return nodeRef; - } + this.nodeService.deleteNode(workingCopyNodeRef); + } + else + { + // Error since the copy aspect is missing + throw new AspectMissingException(ContentModel.ASPECT_COPIEDFROM, workingCopyNodeRef); + } + + return nodeRef; + } /** * @see org.alfresco.service.cmr.coci.CheckOutCheckInService#getWorkingCopy(org.alfresco.service.cmr.repository.NodeRef) @@ -454,6 +458,7 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService // Do a search to find the working copy document ResultSet resultSet = null; + try { resultSet = this.searchService.query( diff --git a/source/java/org/alfresco/repo/content/AbstractContentAccessor.java b/source/java/org/alfresco/repo/content/AbstractContentAccessor.java index efee5c1b4b..2845aa837f 100644 --- a/source/java/org/alfresco/repo/content/AbstractContentAccessor.java +++ b/source/java/org/alfresco/repo/content/AbstractContentAccessor.java @@ -150,14 +150,6 @@ public abstract class AbstractContentAccessor implements ContentAccessor } } - /** - * Derived classes must implement this to help determine if the underlying - * IO Channel is still open. - * - * @return Returns true if the underlying IO Channel is open - */ - protected abstract boolean isChannelOpen(); - public String getContentUrl() { return contentUrl; diff --git a/source/java/org/alfresco/repo/content/AbstractContentReader.java b/source/java/org/alfresco/repo/content/AbstractContentReader.java index a908b500d6..d3483c8b71 100644 --- a/source/java/org/alfresco/repo/content/AbstractContentReader.java +++ b/source/java/org/alfresco/repo/content/AbstractContentReader.java @@ -141,8 +141,7 @@ public abstract class AbstractContentReader extends AbstractContentAccessor impl } } - /** helper implementation for base class */ - protected boolean isChannelOpen() + public synchronized boolean isChannelOpen() { if (channel != null) { diff --git a/source/java/org/alfresco/repo/content/AbstractContentWriter.java b/source/java/org/alfresco/repo/content/AbstractContentWriter.java index 234da69207..30c3e5e35a 100644 --- a/source/java/org/alfresco/repo/content/AbstractContentWriter.java +++ b/source/java/org/alfresco/repo/content/AbstractContentWriter.java @@ -156,8 +156,7 @@ public abstract class AbstractContentWriter extends AbstractContentAccessor impl } } - /** helper implementation for base class */ - protected boolean isChannelOpen() + public synchronized boolean isChannelOpen() { if (channel != null) { diff --git a/source/java/org/alfresco/repo/content/RoutingContentServiceTest.java b/source/java/org/alfresco/repo/content/RoutingContentServiceTest.java index cc89d19e92..99cc4e9b8c 100644 --- a/source/java/org/alfresco/repo/content/RoutingContentServiceTest.java +++ b/source/java/org/alfresco/repo/content/RoutingContentServiceTest.java @@ -23,6 +23,8 @@ import java.io.OutputStream; import javax.transaction.RollbackException; import javax.transaction.UserTransaction; +import junit.framework.TestCase; + import org.alfresco.model.ContentModel; import org.alfresco.repo.content.filestore.FileContentWriter; import org.alfresco.repo.content.transform.ContentTransformer; @@ -43,18 +45,21 @@ import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.BaseSpringTest; +import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.GUID; import org.alfresco.util.PropertyMap; import org.alfresco.util.TempFileProvider; +import org.springframework.context.ApplicationContext; /** * @see org.alfresco.repo.content.RoutingContentService * * @author Derek Hulley */ -public class RoutingContentServiceTest extends BaseSpringTest +public class RoutingContentServiceTest extends TestCase { + private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + private static final String SOME_CONTENT = "ABC"; private static final String TEST_NAMESPACE = "http://www.alfresco.org/test/RoutingContentServiceTest"; @@ -62,24 +67,30 @@ public class RoutingContentServiceTest extends BaseSpringTest private ContentService contentService; private PolicyComponent policyComponent; private NodeService nodeService; + private AuthenticationComponent authenticationComponent; + private UserTransaction txn; private NodeRef rootNodeRef; private NodeRef contentNodeRef; - private AuthenticationComponent authenticationComponent; public RoutingContentServiceTest() { } @Override - public void onSetUpInTransaction() throws Exception + public void setUp() throws Exception { - super.onSetUpInTransaction(); - nodeService = (NodeService) applicationContext.getBean("dbNodeService"); - contentService = (ContentService) applicationContext.getBean(ServiceRegistry.CONTENT_SERVICE.getLocalName()); - this.policyComponent = (PolicyComponent)this.applicationContext.getBean("policyComponent"); - this.authenticationComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent"); + nodeService = (NodeService) ctx.getBean("dbNodeService"); + contentService = (ContentService) ctx.getBean(ServiceRegistry.CONTENT_SERVICE.getLocalName()); + this.policyComponent = (PolicyComponent) ctx.getBean("policyComponent"); + this.authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); + // authenticate this.authenticationComponent.setSystemUserAsCurrentUser(); + + // start the transaction + txn = getUserTransaction(); + txn.begin(); + // create a store and get the root node StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, getName()); if (!nodeService.exists(storeRef)) @@ -103,7 +114,7 @@ public class RoutingContentServiceTest extends BaseSpringTest } @Override - protected void onTearDownInTransaction() throws Exception + public void tearDown() throws Exception { try { @@ -113,12 +124,22 @@ public class RoutingContentServiceTest extends BaseSpringTest { // ignore } - super.onTearDownInTransaction(); + try + { + if (txn != null) + { + txn.rollback(); + } + } + catch (Throwable e) + { + // ignore + } } private UserTransaction getUserTransaction() { - TransactionService transactionService = (TransactionService)applicationContext.getBean("transactionComponent"); + TransactionService transactionService = (TransactionService) ctx.getBean("transactionComponent"); return (UserTransaction) transactionService.getUserTransaction(); } @@ -236,8 +257,8 @@ public class RoutingContentServiceTest extends BaseSpringTest assertFalse("Reader should indicate that content is missing", reader.exists()); // check the indexing doesn't spank everthing - setComplete(); - endTransaction(); + txn.commit(); + txn = null; } /** @@ -405,8 +426,8 @@ public class RoutingContentServiceTest extends BaseSpringTest public void testConcurrentWritesNoTxn() throws Exception { // ensure that the transaction is ended - ofcourse, we need to force a commit - setComplete(); - endTransaction(); + txn.commit(); + txn = null; ContentWriter writer1 = contentService.getWriter(contentNodeRef, ContentModel.PROP_CONTENT, true); ContentWriter writer2 = contentService.getWriter(contentNodeRef, ContentModel.PROP_CONTENT, true); @@ -425,8 +446,8 @@ public class RoutingContentServiceTest extends BaseSpringTest public void testConcurrentWritesWithSingleTxn() throws Exception { // want to operate in a user transaction - setComplete(); - endTransaction(); + txn.commit(); + txn = null; UserTransaction txn = getUserTransaction(); txn.begin(); @@ -472,8 +493,8 @@ public class RoutingContentServiceTest extends BaseSpringTest public synchronized void testConcurrentWritesWithMultipleTxns() throws Exception { // commit node so that threads can see node - setComplete(); - endTransaction(); + txn.commit(); + txn = null; UserTransaction txn = getUserTransaction(); txn.begin(); @@ -527,8 +548,8 @@ public class RoutingContentServiceTest extends BaseSpringTest public void testTransformation() throws Exception { // commit node so that threads can see node - setComplete(); - endTransaction(); + txn.commit(); + txn = null; UserTransaction txn = getUserTransaction(); txn.begin(); @@ -655,4 +676,27 @@ public class RoutingContentServiceTest extends BaseSpringTest } } } + + /** + * Check that the system is able to handle the uploading of content with an unknown mimetype. + * The unknown mimetype should be preserved, but treated just like an octet stream. + */ + public void testUnknownMimetype() throws Exception + { + String bogusMimetype = "text/bamboozle"; + // get a writer onto the node + ContentWriter writer = contentService.getWriter(contentNodeRef, ContentModel.PROP_CONTENT, true); + writer.setMimetype(bogusMimetype); + + // write something in + writer.putContent(SOME_CONTENT); + + // commit the transaction to ensure that it goes in OK + txn.commit(); + + // so far, so good + ContentReader reader = contentService.getReader(contentNodeRef, ContentModel.PROP_CONTENT); + assertNotNull("Should be able to get reader", reader); + assertEquals("Unknown mimetype was changed", bogusMimetype, reader.getMimetype()); + } } diff --git a/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracter.java index 6b743f3156..5ae16fc2ad 100644 --- a/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracter.java +++ b/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracter.java @@ -1,220 +1,220 @@ -/* - * Copyright (C) 2005 Jesper Steen Møller - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.content.metadata; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Map; -import java.util.Set; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.service.cmr.repository.ContentIOException; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.cmr.repository.MimetypeService; -import org.alfresco.service.namespace.QName; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * - * @author Jesper Steen Møller - */ -abstract public class AbstractMetadataExtracter implements MetadataExtracter -{ - protected static Log logger = LogFactory.getLog(AbstractMetadataExtracter.class); - - private MimetypeService mimetypeService; - private MetadataExtracterRegistry registry; - private Set supportedMimetypes; - private double reliability; - private long extractionTime; - - protected AbstractMetadataExtracter(String supportedMimetype, double reliability, long extractionTime) - { - this.supportedMimetypes = Collections.singleton(supportedMimetype); - this.reliability = reliability; - this.extractionTime = extractionTime; - } - - protected AbstractMetadataExtracter(Set supportedMimetypes, double reliability, long extractionTime) - { - this.supportedMimetypes = supportedMimetypes; - this.reliability = reliability; - this.extractionTime = extractionTime; - } - - /** - * Set the registry to register with - * - * @param registry a metadata extracter registry - */ - public void setRegistry(MetadataExtracterRegistry registry) - { - this.registry = registry; - } - - /** - * Helper setter of the mimetype service. This is not always required. - * - * @param mimetypeService - */ - public void setMimetypeService(MimetypeService mimetypeService) - { - this.mimetypeService = mimetypeService; - } - - /** - * @return Returns the mimetype helper - */ - protected MimetypeService getMimetypeService() - { - return mimetypeService; - } - - /** - * Registers this instance of the extracter with the registry. - * - * @see #setRegistry(MetadataExtracterRegistry) - */ - public void register() - { - if (registry == null) - { - logger.warn("Property 'registry' has not been set. Ignoring auto-registration: \n" + - " extracter: " + this); - return; - } - registry.register(this); - } - - /** - * Default reliability check that returns the reliability as configured by the contstructor - * if the mimetype is in the list of supported mimetypes. - * - * @param mimetype the mimetype to check - */ - public double getReliability(String mimetype) - { - if (supportedMimetypes.contains(mimetype)) - return reliability; - else - return 0.0; - } - - public long getExtractionTime() - { - return extractionTime; - } - - /** - * Checks if the mimetype is supported. - * - * @param reader the reader to check - * @throws AlfrescoRuntimeException if the mimetype is not supported - */ - protected void checkReliability(ContentReader reader) - { - String mimetype = reader.getMimetype(); - if (getReliability(mimetype) <= 0.0) - { - throw new AlfrescoRuntimeException( - "Metadata extracter does not support mimetype: \n" + - " reader: " + reader + "\n" + - " supported: " + supportedMimetypes + "\n" + - " extracter: " + this); - } - } - - public final void extract(ContentReader reader, Map destination) throws ContentIOException - { - // check the reliability - checkReliability(reader); - - try - { - extractInternal(reader, destination); - } - catch (Throwable e) - { - throw new ContentIOException("Metadata extraction failed: \n" + - " reader: " + reader, - e); - } - finally - { - // check that the reader was closed - if (!reader.isClosed()) - { - logger.error("Content reader not closed by metadata extracter: \n" + - " reader: " + reader + "\n" + - " extracter: " + this); - } - } - - // done - if (logger.isDebugEnabled()) - { - logger.debug("Completed metadata extraction: \n" + - " reader: " + reader + "\n" + - " extracter: " + this); - } - } - - /** - * Override to provide the necessary extraction logic. Implementations must ensure that the reader - * is closed before the method exits. - * - * @param reader the source of the content - * @param destination the property map to fill - * @throws Throwable an exception - */ - protected abstract void extractInternal(ContentReader reader, Map destination) throws Throwable; - - /** - * Examines a value or string for nulls and adds it to the map (if - * non-empty) - * - * @param prop Alfresco's ContentModel.PROP_ to set. - * @param value Value to set it to - * @param destination Map into which to set it - * @return true, if set, false otherwise - */ - protected boolean trimPut(QName prop, Object value, Map destination) - { - if (value == null) - return false; - if (value instanceof String) - { - String svalue = ((String) value).trim(); - if (svalue.length() > 0) - { - destination.put(prop, svalue); - return true; - } - return false; - } - else if (value instanceof Serializable) - { - destination.put(prop, (Serializable) value); - } - else - { - destination.put(prop, value.toString()); - } - return true; - } -} +/* + * Copyright (C) 2005 Jesper Steen Møller + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.content.metadata; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.repository.ContentIOException; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.namespace.QName; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author Jesper Steen Møller + */ +abstract public class AbstractMetadataExtracter implements MetadataExtracter +{ + protected static Log logger = LogFactory.getLog(AbstractMetadataExtracter.class); + + private MimetypeService mimetypeService; + private MetadataExtracterRegistry registry; + private Set supportedMimetypes; + private double reliability; + private long extractionTime; + + protected AbstractMetadataExtracter(String supportedMimetype, double reliability, long extractionTime) + { + this.supportedMimetypes = Collections.singleton(supportedMimetype); + this.reliability = reliability; + this.extractionTime = extractionTime; + } + + protected AbstractMetadataExtracter(Set supportedMimetypes, double reliability, long extractionTime) + { + this.supportedMimetypes = supportedMimetypes; + this.reliability = reliability; + this.extractionTime = extractionTime; + } + + /** + * Set the registry to register with + * + * @param registry a metadata extracter registry + */ + public void setRegistry(MetadataExtracterRegistry registry) + { + this.registry = registry; + } + + /** + * Helper setter of the mimetype service. This is not always required. + * + * @param mimetypeService + */ + public void setMimetypeService(MimetypeService mimetypeService) + { + this.mimetypeService = mimetypeService; + } + + /** + * @return Returns the mimetype helper + */ + protected MimetypeService getMimetypeService() + { + return mimetypeService; + } + + /** + * Registers this instance of the extracter with the registry. + * + * @see #setRegistry(MetadataExtracterRegistry) + */ + public void register() + { + if (registry == null) + { + logger.warn("Property 'registry' has not been set. Ignoring auto-registration: \n" + + " extracter: " + this); + return; + } + registry.register(this); + } + + /** + * Default reliability check that returns the reliability as configured by the contstructor + * if the mimetype is in the list of supported mimetypes. + * + * @param mimetype the mimetype to check + */ + public double getReliability(String mimetype) + { + if (supportedMimetypes.contains(mimetype)) + return reliability; + else + return 0.0; + } + + public long getExtractionTime() + { + return extractionTime; + } + + /** + * Checks if the mimetype is supported. + * + * @param reader the reader to check + * @throws AlfrescoRuntimeException if the mimetype is not supported + */ + protected void checkReliability(ContentReader reader) + { + String mimetype = reader.getMimetype(); + if (getReliability(mimetype) <= 0.0) + { + throw new AlfrescoRuntimeException( + "Metadata extracter does not support mimetype: \n" + + " reader: " + reader + "\n" + + " supported: " + supportedMimetypes + "\n" + + " extracter: " + this); + } + } + + public final void extract(ContentReader reader, Map destination) throws ContentIOException + { + // check the reliability + checkReliability(reader); + + try + { + extractInternal(reader, destination); + } + catch (Throwable e) + { + throw new ContentIOException("Metadata extraction failed: \n" + + " reader: " + reader, + e); + } + finally + { + // check that the reader was closed + if (!reader.isClosed()) + { + logger.error("Content reader not closed by metadata extracter: \n" + + " reader: " + reader + "\n" + + " extracter: " + this); + } + } + + // done + if (logger.isDebugEnabled()) + { + logger.debug("Completed metadata extraction: \n" + + " reader: " + reader + "\n" + + " extracter: " + this); + } + } + + /** + * Override to provide the necessary extraction logic. Implementations must ensure that the reader + * is closed before the method exits. + * + * @param reader the source of the content + * @param destination the property map to fill + * @throws Throwable an exception + */ + protected abstract void extractInternal(ContentReader reader, Map destination) throws Throwable; + + /** + * Examines a value or string for nulls and adds it to the map (if + * non-empty) + * + * @param prop Alfresco's ContentModel.PROP_ to set. + * @param value Value to set it to + * @param destination Map into which to set it + * @return true, if set, false otherwise + */ + protected boolean trimPut(QName prop, Object value, Map destination) + { + if (value == null) + return false; + if (value instanceof String) + { + String svalue = ((String) value).trim(); + if (svalue.length() > 0) + { + destination.put(prop, svalue); + return true; + } + return false; + } + else if (value instanceof Serializable) + { + destination.put(prop, (Serializable) value); + } + else + { + destination.put(prop, value.toString()); + } + return true; + } +} diff --git a/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracterTest.java b/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracterTest.java index 7f394db9a8..a49d7ecb5c 100644 --- a/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracterTest.java +++ b/source/java/org/alfresco/repo/content/metadata/AbstractMetadataExtracterTest.java @@ -1,116 +1,116 @@ -/* - * Copyright (C) 2005 Jesper Steen Møller - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.content.metadata; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -import junit.framework.TestCase; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.repo.content.filestore.FileContentReader; -import org.alfresco.repo.content.transform.AbstractContentTransformerTest; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.ApplicationContextHelper; -import org.alfresco.util.TempFileProvider; -import org.springframework.context.ApplicationContext; - -/** - * @see org.alfresco.repo.content.metadata.MetadataExtracter - * @see org.alfresco.repo.content.metadata.AbstractMetadataExtracter - * - * @author Jesper Steen Møller - */ -public abstract class AbstractMetadataExtracterTest extends TestCase -{ - private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); - - protected static final String QUICK_TITLE = "The quick brown fox jumps over the lazy dog"; - protected static final String QUICK_DESCRIPTION = "Gym class featuring a brown fox and lazy dog"; - protected static final String QUICK_CREATOR = "Nevin Nollop"; - - protected MimetypeMap mimetypeMap; - - protected abstract MetadataExtracter getExtracter(); - - /** - * Ensures that the temp locations are cleaned out before the tests start - */ - @Override - public void setUp() throws Exception - { - this.mimetypeMap = (MimetypeMap) ctx.getBean("mimetypeService"); - - // perform a little cleaning up - long now = System.currentTimeMillis(); - TempFileProvider.TempFileCleanerJob.removeFiles(now); - } - - /** - * Check that all objects are present - */ - public void testSetUp() throws Exception - { - assertNotNull("MimetypeMap not present", mimetypeMap); - // check that the quick resources are available - File sourceFile = AbstractContentTransformerTest.loadQuickTestFile("txt"); - assertNotNull("quick.* files should be available from Tests", sourceFile); - } - - protected void testExtractFromMimetype(String mimetype) throws Exception - { - Map properties = extractFromMimetype(mimetype); - // check - testCommonMetadata(mimetype, properties); - } - - protected Map extractFromMimetype(String mimetype) throws Exception - { - Map properties = new HashMap(); - - // get the extension for the mimetype - String ext = mimetypeMap.getExtension(mimetype); - - // attempt to get a source file for each mimetype - File sourceFile = AbstractContentTransformerTest.loadQuickTestFile(ext); - if (sourceFile == null) - { - throw new FileNotFoundException("No quick." + ext + " file found for test"); - } - - // construct a reader onto the source file - ContentReader sourceReader = new FileContentReader(sourceFile); - sourceReader.setMimetype(mimetype); - getExtracter().extract(sourceReader, properties); - return properties; - } - - protected void testCommonMetadata(String mimetype, Map properties) - { - assertEquals( - "Property " + ContentModel.PROP_TITLE + " not found for mimetype " + mimetype, - QUICK_TITLE, properties.get(ContentModel.PROP_TITLE)); - assertEquals( - "Property " + ContentModel.PROP_DESCRIPTION + " not found for mimetype " + mimetype, - QUICK_DESCRIPTION, properties.get(ContentModel.PROP_DESCRIPTION)); - } -} +/* + * Copyright (C) 2005 Jesper Steen Møller + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.content.metadata; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.content.filestore.FileContentReader; +import org.alfresco.repo.content.transform.AbstractContentTransformerTest; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.TempFileProvider; +import org.springframework.context.ApplicationContext; + +/** + * @see org.alfresco.repo.content.metadata.MetadataExtracter + * @see org.alfresco.repo.content.metadata.AbstractMetadataExtracter + * + * @author Jesper Steen Møller + */ +public abstract class AbstractMetadataExtracterTest extends TestCase +{ + private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + protected static final String QUICK_TITLE = "The quick brown fox jumps over the lazy dog"; + protected static final String QUICK_DESCRIPTION = "Gym class featuring a brown fox and lazy dog"; + protected static final String QUICK_CREATOR = "Nevin Nollop"; + + protected MimetypeMap mimetypeMap; + + protected abstract MetadataExtracter getExtracter(); + + /** + * Ensures that the temp locations are cleaned out before the tests start + */ + @Override + public void setUp() throws Exception + { + this.mimetypeMap = (MimetypeMap) ctx.getBean("mimetypeService"); + + // perform a little cleaning up + long now = System.currentTimeMillis(); + TempFileProvider.TempFileCleanerJob.removeFiles(now); + } + + /** + * Check that all objects are present + */ + public void testSetUp() throws Exception + { + assertNotNull("MimetypeMap not present", mimetypeMap); + // check that the quick resources are available + File sourceFile = AbstractContentTransformerTest.loadQuickTestFile("txt"); + assertNotNull("quick.* files should be available from Tests", sourceFile); + } + + protected void testExtractFromMimetype(String mimetype) throws Exception + { + Map properties = extractFromMimetype(mimetype); + // check + testCommonMetadata(mimetype, properties); + } + + protected Map extractFromMimetype(String mimetype) throws Exception + { + Map properties = new HashMap(); + + // get the extension for the mimetype + String ext = mimetypeMap.getExtension(mimetype); + + // attempt to get a source file for each mimetype + File sourceFile = AbstractContentTransformerTest.loadQuickTestFile(ext); + if (sourceFile == null) + { + throw new FileNotFoundException("No quick." + ext + " file found for test"); + } + + // construct a reader onto the source file + ContentReader sourceReader = new FileContentReader(sourceFile); + sourceReader.setMimetype(mimetype); + getExtracter().extract(sourceReader, properties); + return properties; + } + + protected void testCommonMetadata(String mimetype, Map properties) + { + assertEquals( + "Property " + ContentModel.PROP_TITLE + " not found for mimetype " + mimetype, + QUICK_TITLE, properties.get(ContentModel.PROP_TITLE)); + assertEquals( + "Property " + ContentModel.PROP_DESCRIPTION + " not found for mimetype " + mimetype, + QUICK_DESCRIPTION, properties.get(ContentModel.PROP_DESCRIPTION)); + } +} diff --git a/source/java/org/alfresco/repo/content/metadata/HtmlMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/HtmlMetadataExtracter.java index 70794df3f5..a1ea0711cb 100644 --- a/source/java/org/alfresco/repo/content/metadata/HtmlMetadataExtracter.java +++ b/source/java/org/alfresco/repo/content/metadata/HtmlMetadataExtracter.java @@ -1,169 +1,169 @@ -/* - * Copyright (C) 2005 Jesper Steen Møller - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.content.metadata; - -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.Serializable; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import javax.swing.text.ChangedCharSetException; -import javax.swing.text.MutableAttributeSet; -import javax.swing.text.html.HTML; -import javax.swing.text.html.HTMLEditorKit; -import javax.swing.text.html.parser.ParserDelegator; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.namespace.QName; - -/** - * - * @author Jesper Steen Møller - */ -public class HtmlMetadataExtracter extends AbstractMetadataExtracter -{ - private static final Set MIMETYPES = new HashSet(5); - static - { - MIMETYPES.add(MimetypeMap.MIMETYPE_HTML); - MIMETYPES.add(MimetypeMap.MIMETYPE_XHTML); - } - - public HtmlMetadataExtracter() - { - super(MIMETYPES, 1.0, 1000); - } - - public void extractInternal(ContentReader reader, Map destination) throws Throwable - { - final Map tempDestination = new HashMap(); - - HTMLEditorKit.ParserCallback callback = new HTMLEditorKit.ParserCallback() - { - StringBuffer title = null; - boolean inHead = false; - - public void handleText(char[] data, int pos) - { - if (title != null) - { - title.append(data); - } - } - - public void handleComment(char[] data, int pos) - { - // Perhaps sniff for Office 9+ metadata in here? - } - - public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) - { - if (HTML.Tag.HEAD.equals(t)) - { - inHead = true; - } - else if (HTML.Tag.TITLE.equals(t) && inHead) - { - title = new StringBuffer(); - } - else - handleSimpleTag(t, a, pos); - } - - public void handleEndTag(HTML.Tag t, int pos) - { - if (HTML.Tag.HEAD.equals(t)) - { - inHead = false; - } - else if (HTML.Tag.TITLE.equals(t) && title != null) - { - trimPut(ContentModel.PROP_TITLE, title.toString(), tempDestination); - title = null; - } - } - - public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) - { - if (HTML.Tag.META.equals(t)) - { - Object nameO = a.getAttribute(HTML.Attribute.NAME); - Object valueO = a.getAttribute(HTML.Attribute.CONTENT); - if (nameO == null || valueO == null) - return; - - String name = nameO.toString(); - - if (name.equalsIgnoreCase("creator") || name.equalsIgnoreCase("author") - || name.equalsIgnoreCase("dc.creator")) - { - trimPut(ContentModel.PROP_AUTHOR, valueO, tempDestination); - } - if (name.equalsIgnoreCase("description") || name.equalsIgnoreCase("dc.description")) - { - trimPut(ContentModel.PROP_DESCRIPTION, valueO, tempDestination); - } - } - } - - public void handleError(String errorMsg, int pos) - { - } - }; - - String charsetGuess = "UTF-8"; - int tries = 0; - while (tries < 3) - { - tempDestination.clear(); - Reader r = null; - InputStream cis = null; - try - { - cis = reader.getContentInputStream(); - // TODO: for now, use default charset; we should attempt to map from html meta-data - r = new InputStreamReader(cis); - HTMLEditorKit.Parser parser = new ParserDelegator(); - parser.parse(r, callback, tries > 0); - destination.putAll(tempDestination); - break; - } - catch (ChangedCharSetException ccse) - { - tries++; - charsetGuess = ccse.getCharSetSpec(); - int begin = charsetGuess.indexOf("charset="); - if (begin > 0) - charsetGuess = charsetGuess.substring(begin + 8, charsetGuess.length()); - reader = reader.getReader(); - } - finally - { - if (r != null) - r.close(); - if (cis != null) - cis.close(); - } - } - } -} +/* + * Copyright (C) 2005 Jesper Steen Møller + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.content.metadata; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.swing.text.ChangedCharSetException; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.html.HTML; +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.parser.ParserDelegator; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.namespace.QName; + +/** + * + * @author Jesper Steen Møller + */ +public class HtmlMetadataExtracter extends AbstractMetadataExtracter +{ + private static final Set MIMETYPES = new HashSet(5); + static + { + MIMETYPES.add(MimetypeMap.MIMETYPE_HTML); + MIMETYPES.add(MimetypeMap.MIMETYPE_XHTML); + } + + public HtmlMetadataExtracter() + { + super(MIMETYPES, 1.0, 1000); + } + + public void extractInternal(ContentReader reader, Map destination) throws Throwable + { + final Map tempDestination = new HashMap(); + + HTMLEditorKit.ParserCallback callback = new HTMLEditorKit.ParserCallback() + { + StringBuffer title = null; + boolean inHead = false; + + public void handleText(char[] data, int pos) + { + if (title != null) + { + title.append(data); + } + } + + public void handleComment(char[] data, int pos) + { + // Perhaps sniff for Office 9+ metadata in here? + } + + public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) + { + if (HTML.Tag.HEAD.equals(t)) + { + inHead = true; + } + else if (HTML.Tag.TITLE.equals(t) && inHead) + { + title = new StringBuffer(); + } + else + handleSimpleTag(t, a, pos); + } + + public void handleEndTag(HTML.Tag t, int pos) + { + if (HTML.Tag.HEAD.equals(t)) + { + inHead = false; + } + else if (HTML.Tag.TITLE.equals(t) && title != null) + { + trimPut(ContentModel.PROP_TITLE, title.toString(), tempDestination); + title = null; + } + } + + public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) + { + if (HTML.Tag.META.equals(t)) + { + Object nameO = a.getAttribute(HTML.Attribute.NAME); + Object valueO = a.getAttribute(HTML.Attribute.CONTENT); + if (nameO == null || valueO == null) + return; + + String name = nameO.toString(); + + if (name.equalsIgnoreCase("creator") || name.equalsIgnoreCase("author") + || name.equalsIgnoreCase("dc.creator")) + { + trimPut(ContentModel.PROP_AUTHOR, valueO, tempDestination); + } + if (name.equalsIgnoreCase("description") || name.equalsIgnoreCase("dc.description")) + { + trimPut(ContentModel.PROP_DESCRIPTION, valueO, tempDestination); + } + } + } + + public void handleError(String errorMsg, int pos) + { + } + }; + + String charsetGuess = "UTF-8"; + int tries = 0; + while (tries < 3) + { + tempDestination.clear(); + Reader r = null; + InputStream cis = null; + try + { + cis = reader.getContentInputStream(); + // TODO: for now, use default charset; we should attempt to map from html meta-data + r = new InputStreamReader(cis); + HTMLEditorKit.Parser parser = new ParserDelegator(); + parser.parse(r, callback, tries > 0); + destination.putAll(tempDestination); + break; + } + catch (ChangedCharSetException ccse) + { + tries++; + charsetGuess = ccse.getCharSetSpec(); + int begin = charsetGuess.indexOf("charset="); + if (begin > 0) + charsetGuess = charsetGuess.substring(begin + 8, charsetGuess.length()); + reader = reader.getReader(); + } + finally + { + if (r != null) + r.close(); + if (cis != null) + cis.close(); + } + } + } +} diff --git a/source/java/org/alfresco/repo/content/metadata/HtmlMetadataExtracterTest.java b/source/java/org/alfresco/repo/content/metadata/HtmlMetadataExtracterTest.java index 24376a1fe4..7867e8df9c 100644 --- a/source/java/org/alfresco/repo/content/metadata/HtmlMetadataExtracterTest.java +++ b/source/java/org/alfresco/repo/content/metadata/HtmlMetadataExtracterTest.java @@ -1,57 +1,57 @@ -/* - * Copyright (C) 2005 Jesper Steen Møller - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.content.metadata; - -import org.alfresco.repo.content.MimetypeMap; - -/** - * @author Jesper Steen Møller - */ -public class HtmlMetadataExtracterTest extends AbstractMetadataExtracterTest -{ - private MetadataExtracter extracter; - - @Override - public void setUp() throws Exception - { - super.setUp(); - extracter = new HtmlMetadataExtracter(); - } - - /** - * @return Returns the same transformer regardless - it is allowed - */ - protected MetadataExtracter getExtracter() - { - return extracter; - } - - public void testReliability() throws Exception - { - double reliability = 0.0; - reliability = extracter.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype text should not be supported", 0.0, reliability); - - reliability = extracter.getReliability(MimetypeMap.MIMETYPE_HTML); - assertEquals("HTML should be supported", 1.0, reliability); - } - - public void testHtmlExtraction() throws Exception - { - testExtractFromMimetype(MimetypeMap.MIMETYPE_HTML); - } -} +/* + * Copyright (C) 2005 Jesper Steen Møller + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.content.metadata; + +import org.alfresco.repo.content.MimetypeMap; + +/** + * @author Jesper Steen Møller + */ +public class HtmlMetadataExtracterTest extends AbstractMetadataExtracterTest +{ + private MetadataExtracter extracter; + + @Override + public void setUp() throws Exception + { + super.setUp(); + extracter = new HtmlMetadataExtracter(); + } + + /** + * @return Returns the same transformer regardless - it is allowed + */ + protected MetadataExtracter getExtracter() + { + return extracter; + } + + public void testReliability() throws Exception + { + double reliability = 0.0; + reliability = extracter.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN); + assertEquals("Mimetype text should not be supported", 0.0, reliability); + + reliability = extracter.getReliability(MimetypeMap.MIMETYPE_HTML); + assertEquals("HTML should be supported", 1.0, reliability); + } + + public void testHtmlExtraction() throws Exception + { + testExtractFromMimetype(MimetypeMap.MIMETYPE_HTML); + } +} diff --git a/source/java/org/alfresco/repo/content/metadata/MetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/MetadataExtracter.java index adc44e99d9..b548016e5d 100644 --- a/source/java/org/alfresco/repo/content/metadata/MetadataExtracter.java +++ b/source/java/org/alfresco/repo/content/metadata/MetadataExtracter.java @@ -1,72 +1,72 @@ -/* - * Copyright (C) 2005 Jesper Steen Møller - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.content.metadata; - -import java.io.Serializable; -import java.util.Map; - -import org.alfresco.service.cmr.repository.ContentIOException; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.namespace.QName; - -/** - * - * @author Jesper Steen Møller - */ -public interface MetadataExtracter -{ - /** - * Provides the approximate accuracy with which this extracter can extract - * metadata for the mimetype. - *

- * - * @param sourceMimetype the source mimetype - * @return Returns a score 0.0 to 1.0. 0.0 indicates that the extraction - * cannot be performed at all. 1.0 indicates that the extraction can - * be performed perfectly. - */ - public double getReliability(String sourceMimetype); - - /** - * Provides an estimate, usually a worst case guess, of how long an - * extraction will take. - *

- * This method is used to determine, up front, which of a set of equally - * reliant transformers will be used for a specific extraction. - * - * @return Returns the approximate number of milliseconds per transformation - */ - public long getExtractionTime(); - - /** - * Extracts the metadata from the content provided by the reader and source - * mimetype to the supplied map. - *

- * The extraction viability can be determined by an up front call to - * {@link #getReliability(String)}. - *

- * The source mimetype must be available on the - * {@link org.alfresco.service.cmr.repository.ContentAccessor#getMimetype()} method - * of the reader. - * - * @param reader the source of the content - * @param destination the destination of the extraction - * @throws ContentIOException if an IO exception occurs - */ - public void extract(ContentReader reader, Map destination) throws ContentIOException; - -} +/* + * Copyright (C) 2005 Jesper Steen Møller + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.content.metadata; + +import java.io.Serializable; +import java.util.Map; + +import org.alfresco.service.cmr.repository.ContentIOException; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.namespace.QName; + +/** + * + * @author Jesper Steen Møller + */ +public interface MetadataExtracter +{ + /** + * Provides the approximate accuracy with which this extracter can extract + * metadata for the mimetype. + *

+ * + * @param sourceMimetype the source mimetype + * @return Returns a score 0.0 to 1.0. 0.0 indicates that the extraction + * cannot be performed at all. 1.0 indicates that the extraction can + * be performed perfectly. + */ + public double getReliability(String sourceMimetype); + + /** + * Provides an estimate, usually a worst case guess, of how long an + * extraction will take. + *

+ * This method is used to determine, up front, which of a set of equally + * reliant transformers will be used for a specific extraction. + * + * @return Returns the approximate number of milliseconds per transformation + */ + public long getExtractionTime(); + + /** + * Extracts the metadata from the content provided by the reader and source + * mimetype to the supplied map. + *

+ * The extraction viability can be determined by an up front call to + * {@link #getReliability(String)}. + *

+ * The source mimetype must be available on the + * {@link org.alfresco.service.cmr.repository.ContentAccessor#getMimetype()} method + * of the reader. + * + * @param reader the source of the content + * @param destination the destination of the extraction + * @throws ContentIOException if an IO exception occurs + */ + public void extract(ContentReader reader, Map destination) throws ContentIOException; + +} diff --git a/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java b/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java index 2365a7065e..e8302e9e76 100644 --- a/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java +++ b/source/java/org/alfresco/repo/content/metadata/MetadataExtracterRegistry.java @@ -1,191 +1,172 @@ -/* - * Copyright (C) 2005 Jesper Steen Møller - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.content.metadata; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.content.MimetypeMap; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Holds and provides the most appropriate metadate extracter for a particular - * mimetype. - *

- * The extracters themselves know how well they are able to extract metadata. - * - * @see org.alfresco.repo.content.metadata.MetadataExtracter - * @author Jesper Steen Møller - */ -public class MetadataExtracterRegistry -{ - private static final Log logger = LogFactory.getLog(MetadataExtracterRegistry.class); - - private List extracters; - private Map extracterCache; - - private MimetypeMap mimetypeMap; - /** Controls read access to the cache */ - private Lock extracterCacheReadLock; - /** controls write access to the cache */ - private Lock extracterCacheWriteLock; - - public MetadataExtracterRegistry() - { - // initialise lists - extracters = new ArrayList(10); - extracterCache = new HashMap(17); - - // create lock objects for access to the cache - ReadWriteLock extractionCacheLock = new ReentrantReadWriteLock(); - extracterCacheReadLock = extractionCacheLock.readLock(); - extracterCacheWriteLock = extractionCacheLock.writeLock(); - } - - /** - * The mimetype map that will be used to check requests against - * - * @param mimetypeMap a map of mimetypes - */ - public void setMimetypeMap(MimetypeMap mimetypeMap) - { - this.mimetypeMap = mimetypeMap; - } - - /** - * Register an instance of an extracter for use - * - * @param extracter an extracter - */ - public void register(MetadataExtracter extracter) - { - if (logger.isDebugEnabled()) - { - logger.debug("Registering metadata extracter: " + extracter); - } - - extracterCacheWriteLock.lock(); - try - { - extracters.add(extracter); - extracterCache.clear(); - } - finally - { - extracterCacheWriteLock.unlock(); - } - } - - /** - * Gets the best metadata extracter. This is a combination of the most - * reliable and the most performant extracter. - *

- * The result is cached for quicker access next time. - * - * @param mimetype the source MIME of the extraction - * @return Returns a metadata extracter that can extract metadata from the - * chosen MIME type. - */ - public MetadataExtracter getExtracter(String sourceMimetype) - { - // check that the mimetypes are valid - if (!mimetypeMap.getMimetypes().contains(sourceMimetype)) - { - throw new AlfrescoRuntimeException("Unknown extraction source mimetype: " + sourceMimetype); - } - - MetadataExtracter extracter = null; - extracterCacheReadLock.lock(); - try - { - if (extracterCache.containsKey(sourceMimetype)) - { - // the translation has been requested before - // it might have been null - return extracterCache.get(sourceMimetype); - } - } - finally - { - extracterCacheReadLock.unlock(); - } - - // the translation has not been requested before - // get a write lock on the cache - // no double check done as it is not an expensive task - extracterCacheWriteLock.lock(); - try - { - // find the most suitable transformer - may be empty list - extracter = findBestExtracter(sourceMimetype); - // store the result even if it is null - extracterCache.put(sourceMimetype, extracter); - return extracter; - } - finally - { - extracterCacheWriteLock.unlock(); - } - } - - /** - * @param sourceMimetype The MIME type under examination - * @return The fastest of the most reliable extracters in extracters - * for the given MIME type, or null if none is available. - */ - private MetadataExtracter findBestExtracter(String sourceMimetype) - { - double bestReliability = -1; - long bestTime = Long.MAX_VALUE; - logger.debug("Finding best extracter for " + sourceMimetype); - - MetadataExtracter bestExtracter = null; - - for (MetadataExtracter ext : extracters) - { - double r = ext.getReliability(sourceMimetype); - if (r <= 0.0) - { - // extraction not achievable - continue; - } - else if (r == bestReliability) - { - long time = ext.getExtractionTime(); - if (time < bestTime) - { - bestExtracter = ext; - bestTime = time; - } - } - else if (r > bestReliability) - { - bestExtracter = ext; - bestReliability = r; - bestTime = ext.getExtractionTime(); - } - } - return bestExtracter; - } +/* + * Copyright (C) 2005 Jesper Steen Møller + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.content.metadata; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Holds and provides the most appropriate metadate extracter for a particular + * mimetype. + *

+ * The extracters themselves know how well they are able to extract metadata. + * + * @see org.alfresco.repo.content.metadata.MetadataExtracter + * @author Jesper Steen Møller + */ +public class MetadataExtracterRegistry +{ + private static final Log logger = LogFactory.getLog(MetadataExtracterRegistry.class); + + private List extracters; + private Map extracterCache; + + /** Controls read access to the cache */ + private Lock extracterCacheReadLock; + /** controls write access to the cache */ + private Lock extracterCacheWriteLock; + + public MetadataExtracterRegistry() + { + // initialise lists + extracters = new ArrayList(10); + extracterCache = new HashMap(17); + + // create lock objects for access to the cache + ReadWriteLock extractionCacheLock = new ReentrantReadWriteLock(); + extracterCacheReadLock = extractionCacheLock.readLock(); + extracterCacheWriteLock = extractionCacheLock.writeLock(); + } + + /** + * Register an instance of an extracter for use + * + * @param extracter an extracter + */ + public void register(MetadataExtracter extracter) + { + if (logger.isDebugEnabled()) + { + logger.debug("Registering metadata extracter: " + extracter); + } + + extracterCacheWriteLock.lock(); + try + { + extracters.add(extracter); + extracterCache.clear(); + } + finally + { + extracterCacheWriteLock.unlock(); + } + } + + /** + * Gets the best metadata extracter. This is a combination of the most + * reliable and the most performant extracter. + *

+ * The result is cached for quicker access next time. + * + * @param mimetype the source MIME of the extraction + * @return Returns a metadata extracter that can extract metadata from the + * chosen MIME type. + */ + public MetadataExtracter getExtracter(String sourceMimetype) + { + MetadataExtracter extracter = null; + extracterCacheReadLock.lock(); + try + { + if (extracterCache.containsKey(sourceMimetype)) + { + // the translation has been requested before + // it might have been null + return extracterCache.get(sourceMimetype); + } + } + finally + { + extracterCacheReadLock.unlock(); + } + + // the translation has not been requested before + // get a write lock on the cache + // no double check done as it is not an expensive task + extracterCacheWriteLock.lock(); + try + { + // find the most suitable transformer - may be empty list + extracter = findBestExtracter(sourceMimetype); + // store the result even if it is null + extracterCache.put(sourceMimetype, extracter); + return extracter; + } + finally + { + extracterCacheWriteLock.unlock(); + } + } + + /** + * @param sourceMimetype The MIME type under examination + * @return The fastest of the most reliable extracters in extracters + * for the given MIME type, or null if none is available. + */ + private MetadataExtracter findBestExtracter(String sourceMimetype) + { + double bestReliability = -1; + long bestTime = Long.MAX_VALUE; + logger.debug("Finding best extracter for " + sourceMimetype); + + MetadataExtracter bestExtracter = null; + + for (MetadataExtracter ext : extracters) + { + double r = ext.getReliability(sourceMimetype); + if (r <= 0.0) + { + // extraction not achievable + continue; + } + else if (r == bestReliability) + { + long time = ext.getExtractionTime(); + if (time < bestTime) + { + bestExtracter = ext; + bestTime = time; + } + } + else if (r > bestReliability) + { + bestExtracter = ext; + bestReliability = r; + bestTime = ext.getExtractionTime(); + } + } + return bestExtracter; + } } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/content/metadata/OfficeMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/OfficeMetadataExtracter.java index 33cec55596..bd3af493a3 100644 --- a/source/java/org/alfresco/repo/content/metadata/OfficeMetadataExtracter.java +++ b/source/java/org/alfresco/repo/content/metadata/OfficeMetadataExtracter.java @@ -1,101 +1,101 @@ -/* - * Copyright (C) 2005 Jesper Steen Møller - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.content.metadata; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.service.cmr.repository.ContentIOException; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.namespace.QName; -import org.apache.poi.hpsf.PropertySet; -import org.apache.poi.hpsf.PropertySetFactory; -import org.apache.poi.hpsf.SummaryInformation; -import org.apache.poi.poifs.eventfilesystem.POIFSReader; -import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent; -import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener; - -/** - * Office file format Metadata Extracter - * - * @author Jesper Steen Møller - */ -public class OfficeMetadataExtracter extends AbstractMetadataExtracter -{ - public static String[] SUPPORTED_MIMETYPES = new String[] { - MimetypeMap.MIMETYPE_WORD, - MimetypeMap.MIMETYPE_EXCEL, - MimetypeMap.MIMETYPE_PPT}; - - public OfficeMetadataExtracter() - { - super(new HashSet(Arrays.asList(SUPPORTED_MIMETYPES)), 1.0, 1000); - } - - public void extractInternal(ContentReader reader, final Map destination) throws Throwable - { - POIFSReaderListener readerListener = new POIFSReaderListener() - { - public void processPOIFSReaderEvent(final POIFSReaderEvent event) - { - try - { - PropertySet ps = PropertySetFactory.create(event.getStream()); - if (ps instanceof SummaryInformation) - { - SummaryInformation si = (SummaryInformation) ps; - - // Titled aspect - trimPut(ContentModel.PROP_TITLE, si.getTitle(), destination); - trimPut(ContentModel.PROP_DESCRIPTION, si.getSubject(), destination); - - // Auditable aspect - trimPut(ContentModel.PROP_CREATED, si.getCreateDateTime(), destination); - trimPut(ContentModel.PROP_MODIFIED, si.getLastSaveDateTime(), destination); - trimPut(ContentModel.PROP_AUTHOR, si.getAuthor(), destination); - } - } - catch (Exception ex) - { - throw new ContentIOException("Property set stream: " + event.getPath() + event.getName(), ex); - } - } - }; - - InputStream is = null; - try - { - is = reader.getContentInputStream(); - POIFSReader poiFSReader = new POIFSReader(); - poiFSReader.registerListener(readerListener, SummaryInformation.DEFAULT_STREAM_NAME); - poiFSReader.read(is); - } - finally - { - if (is != null) - { - try { is.close(); } catch (IOException e) {} - } - } - } -} +/* + * Copyright (C) 2005 Jesper Steen Møller + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.content.metadata; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.repository.ContentIOException; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.namespace.QName; +import org.apache.poi.hpsf.PropertySet; +import org.apache.poi.hpsf.PropertySetFactory; +import org.apache.poi.hpsf.SummaryInformation; +import org.apache.poi.poifs.eventfilesystem.POIFSReader; +import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent; +import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener; + +/** + * Office file format Metadata Extracter + * + * @author Jesper Steen Møller + */ +public class OfficeMetadataExtracter extends AbstractMetadataExtracter +{ + public static String[] SUPPORTED_MIMETYPES = new String[] { + MimetypeMap.MIMETYPE_WORD, + MimetypeMap.MIMETYPE_EXCEL, + MimetypeMap.MIMETYPE_PPT}; + + public OfficeMetadataExtracter() + { + super(new HashSet(Arrays.asList(SUPPORTED_MIMETYPES)), 1.0, 1000); + } + + public void extractInternal(ContentReader reader, final Map destination) throws Throwable + { + POIFSReaderListener readerListener = new POIFSReaderListener() + { + public void processPOIFSReaderEvent(final POIFSReaderEvent event) + { + try + { + PropertySet ps = PropertySetFactory.create(event.getStream()); + if (ps instanceof SummaryInformation) + { + SummaryInformation si = (SummaryInformation) ps; + + // Titled aspect + trimPut(ContentModel.PROP_TITLE, si.getTitle(), destination); + trimPut(ContentModel.PROP_DESCRIPTION, si.getSubject(), destination); + + // Auditable aspect + trimPut(ContentModel.PROP_CREATED, si.getCreateDateTime(), destination); + trimPut(ContentModel.PROP_MODIFIED, si.getLastSaveDateTime(), destination); + trimPut(ContentModel.PROP_AUTHOR, si.getAuthor(), destination); + } + } + catch (Exception ex) + { + throw new ContentIOException("Property set stream: " + event.getPath() + event.getName(), ex); + } + } + }; + + InputStream is = null; + try + { + is = reader.getContentInputStream(); + POIFSReader poiFSReader = new POIFSReader(); + poiFSReader.registerListener(readerListener, SummaryInformation.DEFAULT_STREAM_NAME); + poiFSReader.read(is); + } + finally + { + if (is != null) + { + try { is.close(); } catch (IOException e) {} + } + } + } +} diff --git a/source/java/org/alfresco/repo/content/metadata/PdfBoxMetadataExtracter.java b/source/java/org/alfresco/repo/content/metadata/PdfBoxMetadataExtracter.java index 10b969f3e2..d3296920de 100644 --- a/source/java/org/alfresco/repo/content/metadata/PdfBoxMetadataExtracter.java +++ b/source/java/org/alfresco/repo/content/metadata/PdfBoxMetadataExtracter.java @@ -1,75 +1,75 @@ -/* - * Copyright (C) 2005 Jesper Steen Møller - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.content.metadata; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.util.Calendar; -import java.util.Map; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.namespace.QName; -import org.pdfbox.pdmodel.PDDocument; -import org.pdfbox.pdmodel.PDDocumentInformation; - -/** - * - * @author Jesper Steen Møller - */ -public class PdfBoxMetadataExtracter extends AbstractMetadataExtracter -{ - public PdfBoxMetadataExtracter() - { - super(MimetypeMap.MIMETYPE_PDF, 1.0, 1000); - } - - public void extractInternal(ContentReader reader, Map destination) throws Throwable - { - PDDocument pdf = null; - InputStream is = null; - try - { - is = reader.getContentInputStream(); - // stream the document in - pdf = PDDocument.load(is); - // Scoop out the metadata - PDDocumentInformation docInfo = pdf.getDocumentInformation(); - - trimPut(ContentModel.PROP_AUTHOR, docInfo.getAuthor(), destination); - trimPut(ContentModel.PROP_TITLE, docInfo.getTitle(), destination); - trimPut(ContentModel.PROP_DESCRIPTION, docInfo.getSubject(), destination); - - Calendar created = docInfo.getCreationDate(); - if (created != null) - destination.put(ContentModel.PROP_CREATED, created.getTime()); - } - finally - { - if (is != null) - { - try { is.close(); } catch (IOException e) {} - } - if (pdf != null) - { - try { pdf.close(); } catch (Throwable e) { e.printStackTrace(); } - } - } - } -} +/* + * Copyright (C) 2005 Jesper Steen Møller + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.content.metadata; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.Calendar; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.namespace.QName; +import org.pdfbox.pdmodel.PDDocument; +import org.pdfbox.pdmodel.PDDocumentInformation; + +/** + * + * @author Jesper Steen Møller + */ +public class PdfBoxMetadataExtracter extends AbstractMetadataExtracter +{ + public PdfBoxMetadataExtracter() + { + super(MimetypeMap.MIMETYPE_PDF, 1.0, 1000); + } + + public void extractInternal(ContentReader reader, Map destination) throws Throwable + { + PDDocument pdf = null; + InputStream is = null; + try + { + is = reader.getContentInputStream(); + // stream the document in + pdf = PDDocument.load(is); + // Scoop out the metadata + PDDocumentInformation docInfo = pdf.getDocumentInformation(); + + trimPut(ContentModel.PROP_AUTHOR, docInfo.getAuthor(), destination); + trimPut(ContentModel.PROP_TITLE, docInfo.getTitle(), destination); + trimPut(ContentModel.PROP_DESCRIPTION, docInfo.getSubject(), destination); + + Calendar created = docInfo.getCreationDate(); + if (created != null) + destination.put(ContentModel.PROP_CREATED, created.getTime()); + } + finally + { + if (is != null) + { + try { is.close(); } catch (IOException e) {} + } + if (pdf != null) + { + try { pdf.close(); } catch (Throwable e) { e.printStackTrace(); } + } + } + } +} diff --git a/source/java/org/alfresco/repo/content/metadata/PdfBoxMetadataExtracterTest.java b/source/java/org/alfresco/repo/content/metadata/PdfBoxMetadataExtracterTest.java index 70049a7e92..83cd43f7a5 100644 --- a/source/java/org/alfresco/repo/content/metadata/PdfBoxMetadataExtracterTest.java +++ b/source/java/org/alfresco/repo/content/metadata/PdfBoxMetadataExtracterTest.java @@ -1,43 +1,43 @@ -package org.alfresco.repo.content.metadata; - -import org.alfresco.repo.content.MimetypeMap; - -/** - * @see org.alfresco.repo.content.metadata.PdfBoxMetadataExtracter - * - * @author Jesper Steen Møller - */ -public class PdfBoxMetadataExtracterTest extends AbstractMetadataExtracterTest -{ - private MetadataExtracter extracter; - - @Override - public void setUp() throws Exception - { - super.setUp(); - extracter = new PdfBoxMetadataExtracter(); - } - - /** - * @return Returns the same transformer regardless - it is allowed - */ - protected MetadataExtracter getExtracter() - { - return extracter; - } - - public void testReliability() throws Exception - { - double reliability = 0.0; - reliability = extracter.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN); - assertEquals("Mimetype should not be supported", 0.0, reliability); - - reliability = extracter.getReliability(MimetypeMap.MIMETYPE_PDF); - assertEquals("Mimetype should be supported", 1.0, reliability); - } - - public void testPdfExtraction() throws Exception - { - testExtractFromMimetype(MimetypeMap.MIMETYPE_PDF); - } -} +package org.alfresco.repo.content.metadata; + +import org.alfresco.repo.content.MimetypeMap; + +/** + * @see org.alfresco.repo.content.metadata.PdfBoxMetadataExtracter + * + * @author Jesper Steen Møller + */ +public class PdfBoxMetadataExtracterTest extends AbstractMetadataExtracterTest +{ + private MetadataExtracter extracter; + + @Override + public void setUp() throws Exception + { + super.setUp(); + extracter = new PdfBoxMetadataExtracter(); + } + + /** + * @return Returns the same transformer regardless - it is allowed + */ + protected MetadataExtracter getExtracter() + { + return extracter; + } + + public void testReliability() throws Exception + { + double reliability = 0.0; + reliability = extracter.getReliability(MimetypeMap.MIMETYPE_TEXT_PLAIN); + assertEquals("Mimetype should not be supported", 0.0, reliability); + + reliability = extracter.getReliability(MimetypeMap.MIMETYPE_PDF); + assertEquals("Mimetype should be supported", 1.0, reliability); + } + + public void testPdfExtraction() throws Exception + { + testExtractFromMimetype(MimetypeMap.MIMETYPE_PDF); + } +} diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java index ee82eac135..8369e61f94 100644 --- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformer.java @@ -252,13 +252,13 @@ public abstract class AbstractContentTransformer implements ContentTransformer finally { // check that the reader and writer are both closed - if (!reader.isClosed()) + if (reader.isChannelOpen()) { logger.error("Content reader not closed by transformer: \n" + " reader: " + reader + "\n" + " transformer: " + this); } - if (!writer.isClosed()) + if (writer.isChannelOpen()) { logger.error("Content writer not closed by transformer: \n" + " writer: " + writer + "\n" + diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java index 242499ffc4..8f370dbc47 100644 --- a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java +++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistry.java @@ -25,11 +25,8 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.content.MimetypeMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.util.Assert; /** * Holds and provides the most appropriate content transformer for @@ -47,7 +44,6 @@ public class ContentTransformerRegistry private static final Log logger = LogFactory.getLog(ContentTransformerRegistry.class); private List transformers; - private MimetypeMap mimetypeMap; /** Cache of previously used transactions */ private Map> transformationCache; /** Controls read access to the transformation cache */ @@ -58,11 +54,8 @@ public class ContentTransformerRegistry /** * @param mimetypeMap all the mimetypes available to the system */ - public ContentTransformerRegistry(MimetypeMap mimetypeMap) + public ContentTransformerRegistry() { - Assert.notNull(mimetypeMap, "The MimetypeMap is mandatory"); - this.mimetypeMap = mimetypeMap; - this.transformers = new ArrayList(10); transformationCache = new HashMap>(17); @@ -143,16 +136,6 @@ public class ContentTransformerRegistry */ public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype) { - // check that the mimetypes are valid - if (!mimetypeMap.getMimetypes().contains(sourceMimetype)) - { - throw new AlfrescoRuntimeException("Unknown source mimetype: " + sourceMimetype); - } - if (!mimetypeMap.getMimetypes().contains(targetMimetype)) - { - throw new AlfrescoRuntimeException("Unknown target mimetype: " + targetMimetype); - } - TransformationKey key = new TransformationKey(sourceMimetype, targetMimetype); List transformers = null; transformationCacheReadLock.lock(); diff --git a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java index 0b0ac21f98..dac9c68c14 100644 --- a/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java +++ b/source/java/org/alfresco/repo/content/transform/ContentTransformerRegistryTest.java @@ -69,7 +69,7 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe bytes[i] = (byte)i; } // create the dummyRegistry - dummyRegistry = new ContentTransformerRegistry(mimetypeMap); + dummyRegistry = new ContentTransformerRegistry(); // create some dummy transformers for reliability tests new DummyTransformer(mimetypeMap, dummyRegistry, A, B, 0.3, 10L); new DummyTransformer(mimetypeMap, dummyRegistry, A, B, 0.6, 10L); diff --git a/source/java/org/alfresco/repo/copy/CopyServiceImpl.java b/source/java/org/alfresco/repo/copy/CopyServiceImpl.java index 352c58cd26..660847c5fa 100644 --- a/source/java/org/alfresco/repo/copy/CopyServiceImpl.java +++ b/source/java/org/alfresco/repo/copy/CopyServiceImpl.java @@ -536,7 +536,13 @@ public class CopyServiceImpl implements CopyService ClassDefinition classDefinition = this.dictionaryService.getClass(classRef); if (classDefinition != null) { - // Copy the properties + if (classDefinition.isAspect() == true) + { + // make sure any aspects without any properties or associations are copied + copyDetails.addAspect(classRef); + } + + // Copy the properties Map propertyDefinitions = classDefinition.getProperties(); for (QName propertyName : propertyDefinitions.keySet()) { diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java b/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java index efc473dc4d..50306137e4 100644 --- a/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java +++ b/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java @@ -18,7 +18,9 @@ package org.alfresco.repo.dictionary; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.alfresco.service.cmr.dictionary.AspectDefinition; @@ -52,8 +54,8 @@ public class DictionaryDAOImpl implements DictionaryDAO // Namespace Data Access private NamespaceDAO namespaceDAO; - // Map of namespace to model name - private Map namespaceToModel = new HashMap(); + // Map of Namespace URI usages to Models + private Map> uriToModels = new HashMap>(); // Map of model name to compiled model private Map compiledModels = new HashMap(); @@ -90,7 +92,11 @@ public class DictionaryDAOImpl implements DictionaryDAO { namespaceDAO.removePrefix(namespace.getPrefix()); namespaceDAO.removeURI(namespace.getUri()); - namespaceToModel.remove(namespace.getUri()); + unmapUriToModel(namespace.getUri(), previousVersion); + } + for (M2Namespace importNamespace : previousVersion.getM2Model().getImports()) + { + unmapUriToModel(importNamespace.getUri(), previousVersion); } } @@ -99,7 +105,11 @@ public class DictionaryDAOImpl implements DictionaryDAO { namespaceDAO.addURI(namespace.getUri()); namespaceDAO.addPrefix(namespace.getPrefix(), namespace.getUri()); - namespaceToModel.put(namespace.getUri(), modelName); + mapUriToModel(namespace.getUri(), compiledModel); + } + for (M2Namespace importNamespace : model.getImports()) + { + mapUriToModel(importNamespace.getUri(), compiledModel); } // Publish new Model Definition @@ -115,6 +125,7 @@ public class DictionaryDAOImpl implements DictionaryDAO } } + /** * @see org.alfresco.repo.dictionary.DictionaryDAO#removeModel(org.alfresco.service.namespace.QName) */ @@ -129,7 +140,7 @@ public class DictionaryDAOImpl implements DictionaryDAO { namespaceDAO.removePrefix(namespace.getPrefix()); namespaceDAO.removeURI(namespace.getUri()); - namespaceToModel.remove(namespace.getUri()); + unmapUriToModel(namespace.getUri(), compiledModel); } // Remove the model from the list @@ -137,18 +148,61 @@ public class DictionaryDAOImpl implements DictionaryDAO } } + + /** + * Map Namespace URI to Model + * + * @param uri namespace uri + * @param model model + */ + private void mapUriToModel(String uri, CompiledModel model) + { + List models = uriToModels.get(uri); + if (models == null) + { + models = new ArrayList(); + uriToModels.put(uri, models); + } + if (!models.contains(model)) + { + models.add(model); + } + } + /** - * @param uri the namespace uri - * @return the compiled model which defines the specified namespace + * Unmap Namespace URI from Model + * + * @param uri namespace uri + * @param model model */ - private CompiledModel getCompiledModelForNamespace(String uri) + private void unmapUriToModel(String uri, CompiledModel model) { - QName modelName = namespaceToModel.get(uri); - return (modelName == null) ? null : getCompiledModel(modelName); + List models = uriToModels.get(uri); + if (models != null) + { + models.remove(model); + } + } + + + /** + * Get Models mapped to Namespace Uri + * + * @param uri namespace uri + * @return mapped models + */ + private List getModelsForUri(String uri) + { + List models = uriToModels.get(uri); + if (models == null) + { + models = Collections.emptyList(); + } + return models; } - + /** * @param modelName the model name * @return the compiled model of the given name @@ -170,8 +224,16 @@ public class DictionaryDAOImpl implements DictionaryDAO */ public DataTypeDefinition getDataType(QName typeName) { - CompiledModel model = getCompiledModelForNamespace(typeName.getNamespaceURI()); - return (model == null) ? null : model.getDataType(typeName); + List models = getModelsForUri(typeName.getNamespaceURI()); + for (CompiledModel model : models) + { + DataTypeDefinition dataType = model.getDataType(typeName); + if (dataType != null) + { + return dataType; + } + } + return null; } @@ -207,8 +269,16 @@ public class DictionaryDAOImpl implements DictionaryDAO */ public TypeDefinition getType(QName typeName) { - CompiledModel model = getCompiledModelForNamespace(typeName.getNamespaceURI()); - return (model == null) ? null : model.getType(typeName); + List models = getModelsForUri(typeName.getNamespaceURI()); + for (CompiledModel model : models) + { + TypeDefinition type = model.getType(typeName); + if (type != null) + { + return type; + } + } + return null; } @@ -217,8 +287,16 @@ public class DictionaryDAOImpl implements DictionaryDAO */ public AspectDefinition getAspect(QName aspectName) { - CompiledModel model = getCompiledModelForNamespace(aspectName.getNamespaceURI()); - return (model == null) ? null : model.getAspect(aspectName); + List models = getModelsForUri(aspectName.getNamespaceURI()); + for (CompiledModel model : models) + { + AspectDefinition aspect = model.getAspect(aspectName); + if (aspect != null) + { + return aspect; + } + } + return null; } @@ -227,8 +305,16 @@ public class DictionaryDAOImpl implements DictionaryDAO */ public ClassDefinition getClass(QName className) { - CompiledModel model = getCompiledModelForNamespace(className.getNamespaceURI()); - return (model == null) ? null : model.getClass(className); + List models = getModelsForUri(className.getNamespaceURI()); + for (CompiledModel model : models) + { + ClassDefinition classDef = model.getClass(className); + if (classDef != null) + { + return classDef; + } + } + return null; } @@ -237,23 +323,52 @@ public class DictionaryDAOImpl implements DictionaryDAO */ public PropertyDefinition getProperty(QName propertyName) { - CompiledModel model = getCompiledModelForNamespace(propertyName.getNamespaceURI()); - return (model == null) ? null : model.getProperty(propertyName); + List models = getModelsForUri(propertyName.getNamespaceURI()); + for (CompiledModel model : models) + { + PropertyDefinition propDef = model.getProperty(propertyName); + if (propDef != null) + { + return propDef; + } + } + return null; } + + /* (non-Javadoc) + * @see org.alfresco.repo.dictionary.ModelQuery#getConstraint(org.alfresco.service.namespace.QName) + */ public ConstraintDefinition getConstraint(QName constraintQName) { - CompiledModel model = getCompiledModelForNamespace(constraintQName.getNamespaceURI()); - return (model == null) ? null : model.getConstraint(constraintQName); + List models = getModelsForUri(constraintQName.getNamespaceURI()); + for (CompiledModel model : models) + { + ConstraintDefinition constraintDef = model.getConstraint(constraintQName); + if (constraintDef != null) + { + return constraintDef; + } + } + return null; } + /* (non-Javadoc) * @see org.alfresco.repo.dictionary.impl.ModelQuery#getAssociation(org.alfresco.repo.ref.QName) */ public AssociationDefinition getAssociation(QName assocName) { - CompiledModel model = getCompiledModelForNamespace(assocName.getNamespaceURI()); - return (model == null) ? null : model.getAssociation(assocName); + List models = getModelsForUri(assocName.getNamespaceURI()); + for (CompiledModel model : models) + { + AssociationDefinition assocDef = model.getAssociation(assocName); + if (assocDef != null) + { + return assocDef; + } + } + return null; } diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java b/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java index bae285a5ea..1552ef870f 100644 --- a/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java +++ b/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java @@ -36,7 +36,6 @@ import org.alfresco.service.cmr.dictionary.ModelDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.namespace.QName; -import org.alfresco.service.namespace.RegexQNamePattern; public class DictionaryDAOTest extends TestCase @@ -186,6 +185,15 @@ public class DictionaryDAOTest extends TestCase ClassDefinition fileClassDef = service.getClass(testFileQName); assertTrue("File type should have the archive flag", fileClassDef.isArchive()); + QName testFileDerivedQName = QName.createQName(TEST_URL, "file-derived"); + ClassDefinition fileDerivedClassDef = service.getClass(testFileDerivedQName); + assertTrue("Direct derived File type should have the archive flag", fileDerivedClassDef.isArchive()); + + QName testFileDerivedNoArchiveQName = QName.createQName(TEST_URL, "file-derived-no-archive"); + ClassDefinition fileDerivedNoArchiveClassDef = service.getClass(testFileDerivedNoArchiveQName); + assertFalse("Derived File with archive override type should NOT have the archive flag", + fileDerivedNoArchiveClassDef.isArchive()); + QName testFolderQName = QName.createQName(TEST_URL, "folder"); ClassDefinition folderClassDef = service.getClass(testFolderQName); assertFalse("Folder type should not have the archive flag", folderClassDef.isArchive()); diff --git a/source/java/org/alfresco/repo/dictionary/M2Class.java b/source/java/org/alfresco/repo/dictionary/M2Class.java index 7cece04111..a08f4dd88c 100644 --- a/source/java/org/alfresco/repo/dictionary/M2Class.java +++ b/source/java/org/alfresco/repo/dictionary/M2Class.java @@ -32,7 +32,7 @@ public abstract class M2Class private String title = null; private String description = null; private String parentName = null; - private boolean archive = false; + private Boolean archive = null; private List properties = new ArrayList(); private List propertyOverrides = new ArrayList(); @@ -92,14 +92,14 @@ public abstract class M2Class } - public boolean isArchive() + public Boolean getArchive() { return archive; } public void setArchive(boolean archive) { - this.archive = archive; + this.archive = Boolean.valueOf(archive); } public M2Property createProperty(String name) diff --git a/source/java/org/alfresco/repo/dictionary/M2ClassDefinition.java b/source/java/org/alfresco/repo/dictionary/M2ClassDefinition.java index 7b759472de..0fd69bcda6 100644 --- a/source/java/org/alfresco/repo/dictionary/M2ClassDefinition.java +++ b/source/java/org/alfresco/repo/dictionary/M2ClassDefinition.java @@ -46,7 +46,6 @@ import org.alfresco.service.namespace.QName; protected M2Class m2Class; protected QName name; protected QName parentName = null; - protected boolean archive = false; private Map propertyOverrides = new HashMap(); private Map properties = new HashMap(); @@ -57,8 +56,9 @@ import org.alfresco.service.namespace.QName; private List defaultAspects = new ArrayList(); private List defaultAspectNames = new ArrayList(); private List inheritedDefaultAspects = new ArrayList(); + private Boolean archive = null; + private Boolean inheritedArchive = null; - /** * Construct * @@ -74,7 +74,7 @@ import org.alfresco.service.namespace.QName; // Resolve Names this.name = QName.createQName(m2Class.getName(), resolver); - this.archive = m2Class.isArchive(); + this.archive = m2Class.getArchive(); if (m2Class.getParentName() != null && m2Class.getParentName().length() > 0) { this.parentName = QName.createQName(m2Class.getParentName(), resolver); @@ -280,6 +280,13 @@ import org.alfresco.service.namespace.QName; inheritedDefaultAspects.add(def); } } + + // resolve archive inheritance + if (parentClass != null && archive == null) + { + // archive not explicitly set on this class and there is a parent class + inheritedArchive = ((M2ClassDefinition)parentClass).isArchive(); + } } /* (non-Javadoc) @@ -340,8 +347,23 @@ import org.alfresco.service.namespace.QName; return (m2Class instanceof M2Aspect); } + /** + * @return Returns the archive flag, which defaults to false + */ public boolean isArchive() { + if (archive == null) + { + if (inheritedArchive != null) + { + return inheritedArchive.booleanValue(); + } + else + { + // default to false + return false; + } + } return archive; } diff --git a/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml b/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml index 32e074b425..fc8748f662 100644 --- a/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml +++ b/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml @@ -150,6 +150,15 @@ + + test:file + + + + test:file + false + + test:base diff --git a/source/java/org/alfresco/repo/importer/importercomponent_test.xml b/source/java/org/alfresco/repo/importer/importercomponent_test.xml index 27b6dd6200..d5fd119201 100644 --- a/source/java/org/alfresco/repo/importer/importercomponent_test.xml +++ b/source/java/org/alfresco/repo/importer/importercomponent_test.xml @@ -15,7 +15,6 @@ System - true diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java index aefc09f3e1..3fbf309946 100644 --- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java +++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java @@ -70,7 +70,7 @@ public class FileFolderServiceImpl implements FileFolderService "[not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" + " and (subtypeOf('" + ContentModel.TYPE_FOLDER + "'))]"; - /** Shallow search for all files and folders */ + /** Shallow search for files and folders with a name pattern */ private static final String XPATH_QUERY_SHALLOW_ALL = "./*" + "[like(@cm:name, $cm:name, false)" + diff --git a/source/java/org/alfresco/repo/node/TemporaryAspect.java b/source/java/org/alfresco/repo/node/TemporaryAspect.java new file mode 100644 index 0000000000..ca8a5610fb --- /dev/null +++ b/source/java/org/alfresco/repo/node/TemporaryAspect.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.node; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.copy.CopyServicePolicies; +import org.alfresco.repo.policy.JavaBehaviour; +import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.repo.policy.PolicyScope; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +/** + * Registers and contains the behaviour specific to the + * {@link org.alfresco.model.ContentModel#ASPECT_TEMPORARY temporary aspect}. + * + * @author gavinc + */ +public class TemporaryAspect implements CopyServicePolicies.OnCopyNodePolicy +{ + // Dependencies + private PolicyComponent policyComponent; + + /** + * @param policyComponent the policy component to register behaviour with + */ + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + + /** + * Initialise the Temporary Aspect + *

+ * Ensures that the {@link ContentModel#ASPECT_TEMPORARY temporary aspect} + * copy behaviour is disabled when update copies are performed. + */ + public void init() + { + // disable copy for referencable aspect + this.policyComponent.bindClassBehaviour( + QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyNode"), + ContentModel.ASPECT_TEMPORARY, + new JavaBehaviour(this, "onCopyNode")); + } + + /** + * Does nothing + */ + public void onCopyNode( + QName classRef, + NodeRef sourceNodeRef, + StoreRef destinationStoreRef, + boolean copyToNewNode, + PolicyScope copyDetails) + { + if (copyToNewNode) + { + copyDetails.addAspect(ContentModel.ASPECT_TEMPORARY); + } + else + { + // don't copy if this is an update operation + } + } +} diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index ab9b11dead..18a54f4682 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -645,10 +645,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl public void deleteNode(NodeRef nodeRef) { - boolean isArchivedNode = false; + boolean isArchivedNode = false; + boolean requiresDelete = false; - // Invoke policy behaviours - invokeBeforeDeleteNode(nodeRef); + // Invoke policy behaviours + invokeBeforeDeleteNode(nodeRef); // get the node Node node = getNodeNotNull(nodeRef); @@ -659,11 +660,27 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Set nodeAspectQNames = node.getAspects(); // check if we need to archive the node - StoreRef storeRef = nodeRef.getStoreRef(); - StoreRef archiveStoreRef = storeArchiveMap.getArchiveMap().get(storeRef); - // get the type and check if we need archiving - TypeDefinition typeDef = dictionaryService.getType(node.getTypeQName()); - if (typeDef == null || !typeDef.isArchive() || archiveStoreRef == null) + StoreRef archiveStoreRef = null; + if (nodeAspectQNames.contains(ContentModel.ASPECT_TEMPORARY)) + { + // the node has the temporary aspect meaning + // it can not be archived + requiresDelete = true; + isArchivedNode = false; + } + else + { + StoreRef storeRef = nodeRef.getStoreRef(); + archiveStoreRef = storeArchiveMap.getArchiveMap().get(storeRef); + // get the type and check if we need archiving + TypeDefinition typeDef = dictionaryService.getType(node.getTypeQName()); + if (typeDef == null || !typeDef.isArchive() || archiveStoreRef == null) + { + requiresDelete = true; + } + } + + if (requiresDelete) { // perform a normal deletion nodeDaoService.deleteNode(node, true); diff --git a/source/java/org/alfresco/repo/security/permissions/impl/ExceptionTranslatorMethodInterceptor.java b/source/java/org/alfresco/repo/security/permissions/impl/ExceptionTranslatorMethodInterceptor.java index ff6e421707..fc9a769f05 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/ExceptionTranslatorMethodInterceptor.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/ExceptionTranslatorMethodInterceptor.java @@ -27,6 +27,7 @@ import org.springframework.dao.InvalidDataAccessApiUsageException; public class ExceptionTranslatorMethodInterceptor implements MethodInterceptor { private static final String MSG_ACCESS_DENIED = "permissions.err_access_denied"; + private static final String MSG_READ_ONLY = "permissions.err_read_only"; public ExceptionTranslatorMethodInterceptor() { @@ -46,7 +47,7 @@ public class ExceptionTranslatorMethodInterceptor implements MethodInterceptor catch (InvalidDataAccessApiUsageException e) { // this usually occurs when the server is in read-only mode - throw new AccessDeniedException(MSG_ACCESS_DENIED, e); + throw new AccessDeniedException(MSG_READ_ONLY, e); } } } diff --git a/source/java/org/alfresco/service/cmr/repository/ContentAccessor.java b/source/java/org/alfresco/service/cmr/repository/ContentAccessor.java index 6d29a28f75..2100e13bd8 100644 --- a/source/java/org/alfresco/service/cmr/repository/ContentAccessor.java +++ b/source/java/org/alfresco/service/cmr/repository/ContentAccessor.java @@ -25,6 +25,13 @@ import org.alfresco.service.transaction.TransactionService; */ public interface ContentAccessor { + /** + * Gets the open/close state of the underlying IO Channel. + * + * @return Returns true if the underlying IO Channel is open + */ + public boolean isChannelOpen(); + /** * Use this method to register any interest in events against underlying * content streams.