From 0e3da160a244261e1e64006b7501e1dab0fb0353 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Mon, 29 Jan 2007 14:08:52 +0000 Subject: [PATCH] Merged DEV\EXTENSIONS to HEAD svn merge svn://svn.alfresco.com:3691/alfresco/BRANCHES/DEV/EXTENSIONS@4848 svn://svn.alfresco.com:3691/alfresco/BRANCHES/DEV/EXTENSIONS@4850 . Added RegistryService and registryService beans Create ConfigurableService and moved the configurableService bean to be a low-level (untransactioned) component git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4955 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/core-services-context.xml | 65 ++-- config/alfresco/public-services-context.xml | 57 ++++ .../repo/admin/registry/RegistryService.java | 44 +++ .../admin/registry/RegistryServiceImpl.java | 303 ++++++++++++++++++ .../registry/RegistryServiceImplTest.java | 104 ++++++ .../org/alfresco/repo/rule/BaseRuleTest.java | 2 +- 6 files changed, 535 insertions(+), 40 deletions(-) create mode 100644 source/java/org/alfresco/repo/admin/registry/RegistryService.java create mode 100644 source/java/org/alfresco/repo/admin/registry/RegistryServiceImpl.java create mode 100644 source/java/org/alfresco/repo/admin/registry/RegistryServiceImplTest.java diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index 57175cdbd3..767a32a0c5 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -255,31 +255,10 @@ - - - org.alfresco.repo.search.Indexer + + + - - - - - - - - - - - - - indexerComponent - @@ -794,24 +773,32 @@ - - - org.alfresco.repo.configuration.ConfigurableService + + + - - + + + + + + - - - - - - + + - - - ${server.transaction.mode.default} - + + + + + + + + + system://system + + + /sys:system-registry diff --git a/config/alfresco/public-services-context.xml b/config/alfresco/public-services-context.xml index 11a9027c0c..2b15e9e115 100644 --- a/config/alfresco/public-services-context.xml +++ b/config/alfresco/public-services-context.xml @@ -1263,4 +1263,61 @@ + + + + + org.alfresco.repo.configuration.ConfigurableService + + + + + + + + + + + + + + + + + + ${server.transaction.mode.readOnly} + ${server.transaction.mode.readOnly} + ${server.transaction.mode.default} + + + + + + + + + org.alfresco.repo.admin.registry.RegistryService + + + + + + + + + + + + + + + + + + ${server.transaction.mode.readOnly} + ${server.transaction.mode.default} + + + + diff --git a/source/java/org/alfresco/repo/admin/registry/RegistryService.java b/source/java/org/alfresco/repo/admin/registry/RegistryService.java new file mode 100644 index 0000000000..338d0a02c3 --- /dev/null +++ b/source/java/org/alfresco/repo/admin/registry/RegistryService.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2007 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.admin.registry; + +import java.io.Serializable; + +/** + * Interface for service providing access to key-value pairs for storage + * of system-controlled metadata. + * + * @author Derek Hulley + */ +public interface RegistryService +{ + /** + * Assign a value to the registry key, which must be of the form /a/b/c. + * + * @param key the registry key path delimited with '/'. + * @param value any value that can be stored in the repository. + */ + void addValue(String key, Serializable value); + + /** + * @param key the registry key path delimited with '/'. + * @return Returns the value stored in the key. + * + * @see #addValue(String, Serializable) + */ + Serializable getValue(String key); +} diff --git a/source/java/org/alfresco/repo/admin/registry/RegistryServiceImpl.java b/source/java/org/alfresco/repo/admin/registry/RegistryServiceImpl.java new file mode 100644 index 0000000000..a73cd97acc --- /dev/null +++ b/source/java/org/alfresco/repo/admin/registry/RegistryServiceImpl.java @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2007 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.admin.registry; + +import java.io.Serializable; +import java.util.List; +import java.util.StringTokenizer; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; +import org.alfresco.util.PropertyCheck; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Implementation of registry service to provide generic storage + * and retrieval of system-related metadata. + * + * @author Derek Hulley + */ +public class RegistryServiceImpl implements RegistryService +{ + private static Log logger = LogFactory.getLog(RegistryServiceImpl.class); + + private AuthenticationComponent authenticationComponent; + private NamespaceService namespaceService; + private NodeService nodeService; + private SearchService searchService; + private StoreRef registryStoreRef; + private String registryRootPath; + + public void setAuthenticationComponent(AuthenticationComponent authenticationComponent) + { + this.authenticationComponent = authenticationComponent; + } + + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + public void setSearchService(SearchService searchService) + { + this.searchService = searchService; + } + + /** + * @param registryStoreRef the store in which the registry root is found + */ + public void setRegistryStoreRef(StoreRef registryStoreRef) + { + this.registryStoreRef = registryStoreRef; + } + + /** + * @see #setRegistryStoreRef(StoreRef) + */ + public void setRegistryStore(String registryStore) + { + this.setRegistryStoreRef(new StoreRef(registryStore)); + } + + /** + * A root path e.g. /sys:systemRegistry + * + * @param registryRootPath the path to the root of the registry + */ + public void setRegistryRootPath(String registryRootPath) + { + this.registryRootPath = registryRootPath; + } + + public void init() + { + // Check the properties + PropertyCheck.mandatory(this, "authenticationComponent", authenticationComponent); + PropertyCheck.mandatory(this, "namespaceService", namespaceService); + PropertyCheck.mandatory(this, "nodeService", nodeService); + PropertyCheck.mandatory(this, "registryRootPath", searchService); + PropertyCheck.mandatory(this, "registryStore", registryStoreRef); + PropertyCheck.mandatory(this, "registryRootPath", registryRootPath); + } + + private NodeRef getRegistryRootNodeRef() + { + NodeRef registryRootNodeRef = null; + // Ensure that the registry root node is present + ResultSet rs = searchService.query(registryStoreRef, SearchService.LANGUAGE_XPATH, registryRootPath); + if (rs.length() == 0) + { + throw new AlfrescoRuntimeException( + "Registry root not present: \n" + + " Store: " + registryStoreRef + "\n" + + " Path: " + registryRootPath); + } + else if (rs.length() > 1) + { + throw new AlfrescoRuntimeException( + "Registry root path has multiple targets: \n" + + " Store: " + registryStoreRef + "\n" + + " Path: " + registryRootPath); + } + else + { + registryRootNodeRef = rs.getNodeRef(0); + } + // Check the root + QName typeQName = nodeService.getType(registryRootNodeRef); + if (!typeQName.equals(ContentModel.TYPE_CONTAINER)) + { + throw new AlfrescoRuntimeException( + "Registry root is not of type " + ContentModel.TYPE_CONTAINER + ": \n" + + " Node: " + registryRootNodeRef + "\n" + + " Type: " + typeQName); + } + // Done + if (logger.isDebugEnabled()) + { + logger.debug( + "Found root for registry: \n" + + " Store: " + registryStoreRef + "\n" + + " Path : " + registryRootPath + "\n" + + " Root: " + registryRootNodeRef); + } + return registryRootNodeRef; + } + + /** + * @return Returns a pair representing the node path and the property name + */ + private Pair splitKey(String key) + { + int index = key.lastIndexOf('/'); + Pair result = null; + if (index < 0) // It is just a property + { + result = new Pair("/", key); + } + else + { + String propertyName = key.substring(index + 1, key.length()); + if (propertyName.length() == 0) + { + throw new IllegalArgumentException("The registry key is invalid: " + key); + } + result = new Pair(key.substring(0, index), propertyName); + } + // done + return result; + } + + /** + * @return Returns the node and property name represented by the key or null + * if it doesn't exist and was not allowed to be created + */ + private Pair getPath(String key, boolean create) + { + // Get the root + NodeRef currentNodeRef = getRegistryRootNodeRef(); + // Split the key + Pair keyPair = splitKey(key); + // Parse the key + StringTokenizer tokenizer = new StringTokenizer(keyPair.getFirst(), "/"); + // Find the node and property to put the value + while (tokenizer.hasMoreTokens()) + { + String token = tokenizer.nextToken(); + String name = QName.createValidLocalName(token); + QName qname = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, name); + + // Find the node + List childAssocRefs = nodeService.getChildAssocs( + currentNodeRef, + ContentModel.ASSOC_CHILDREN, + qname); + int size = childAssocRefs.size(); + if (size == 0) // Found nothing with that path + { + if (create) // Must create the path + { + // Create the node + currentNodeRef = nodeService.createNode( + currentNodeRef, + ContentModel.ASSOC_CHILDREN, + qname, + ContentModel.TYPE_CONTAINER).getChildRef(); + } + else + { + // There is no node and we are not allowed to create it + currentNodeRef = null; + break; + } + } + else // Found some results for that path + { + if (size > 1 && create) // More than one association by that name + { + // Too many, so trim it down + boolean first = true; + for (ChildAssociationRef assocRef : childAssocRefs) + { + if (first) + { + first = false; + continue; + } + // Remove excess assocs + nodeService.removeChildAssociation(assocRef); + } + } + // Use the first one + currentNodeRef = childAssocRefs.get(0).getChildRef(); + } + } + // Create the result + QName propertyQName = QName.createQName( + NamespaceService.SYSTEM_MODEL_1_0_URI, + QName.createValidLocalName(keyPair.getSecond())); + Pair resultPair = new Pair(currentNodeRef, propertyQName); + // done + if (logger.isDebugEnabled()) + { + logger.debug("Converted registry key: \n" + + " key pair: " + keyPair + "\n" + + " result: " + resultPair); + } + if (resultPair.getFirst() == null) + { + return null; + } + else + { + return resultPair; + } + } + + /** + * @inheritDoc + */ + public void addValue(String key, Serializable value) + { + // Get the path, with creation support + Pair keyPair = getPath(key, true); + // We know that the node exists, so just set the value + nodeService.setProperty(keyPair.getFirst(), keyPair.getSecond(), value); + // Done + if (logger.isDebugEnabled()) + { + logger.debug("Added value to registry: \n" + + " Key: " + key + "\n" + + " Value: " + value); + } + } + + public Serializable getValue(String key) + { + // Get the path, without creating + Pair keyPair = getPath(key, false); + Serializable value = null; + if (keyPair != null) + { + value = nodeService.getProperty(keyPair.getFirst(), keyPair.getSecond()); + } + // Done + if (logger.isDebugEnabled()) + { + logger.debug("Retrieved value from registry: \n" + + " Key: " + key + "\n" + + " Value: " + value); + } + return value; + } +} diff --git a/source/java/org/alfresco/repo/admin/registry/RegistryServiceImplTest.java b/source/java/org/alfresco/repo/admin/registry/RegistryServiceImplTest.java new file mode 100644 index 0000000000..42a454f882 --- /dev/null +++ b/source/java/org/alfresco/repo/admin/registry/RegistryServiceImplTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2007 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.admin.registry; + +import junit.framework.TestCase; + +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.context.ApplicationContext; + +/** + * @see org.alfresco.repo.admin.registry.RegistryService + * + * @author Derek Hulley + */ +public class RegistryServiceImplTest extends TestCase +{ + private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + private AuthenticationComponent authenticationComponent; + private RegistryService registryService; + + @Override + protected void setUp() throws Exception + { + authenticationComponent = (AuthenticationComponent) ctx.getBean("AuthenticationComponent"); + registryService = (RegistryService) ctx.getBean("RegistryService"); + + // Run as admin + authenticationComponent.setSystemUserAsCurrentUser(); + } + + @Override + protected void tearDown() throws Exception + { + // Clear authentication + try + { + authenticationComponent.clearCurrentSecurityContext(); + } + catch (Throwable e) + { + e.printStackTrace(); + } + } + + public void testSetup() throws Exception + { + } + + private static final Long VALUE_ONE = 1L; + private static final Long VALUE_TWO = 2L; + private static final Long VALUE_THREE = 3L; + private static final String KEY_A_B_C_1 = "/a/b/c/1"; + private static final String KEY_A_B_C_2 = "/a/b/c/2"; + private static final String KEY_A_B_C_3 = "/a/b/c/3"; + private static final String KEY_A_B_C_D_1 = "/a/b/c/d/1"; + private static final String KEY_A_B_C_D_2 = "/a/b/c/d/2"; + private static final String KEY_A_B_C_D_3 = "/a/b/c/d/3"; + private static final String KEY_SPECIAL = "/me & you/ whatever"; + /** + * General writing and reading back. + */ + public void testProperUsage() throws Exception + { + registryService.addValue(KEY_A_B_C_1, VALUE_ONE); + registryService.addValue(KEY_A_B_C_2, VALUE_TWO); + registryService.addValue(KEY_A_B_C_3, VALUE_THREE); + registryService.addValue(KEY_A_B_C_D_1, VALUE_ONE); + registryService.addValue(KEY_A_B_C_D_2, VALUE_TWO); + registryService.addValue(KEY_A_B_C_D_3, VALUE_THREE); + + assertEquals("Incorrect value from service registry", VALUE_ONE, registryService.getValue(KEY_A_B_C_1)); + assertEquals("Incorrect value from service registry", VALUE_TWO, registryService.getValue(KEY_A_B_C_2)); + assertEquals("Incorrect value from service registry", VALUE_THREE, registryService.getValue(KEY_A_B_C_3)); + assertEquals("Incorrect value from service registry", VALUE_ONE, registryService.getValue(KEY_A_B_C_D_1)); + assertEquals("Incorrect value from service registry", VALUE_TWO, registryService.getValue(KEY_A_B_C_D_2)); + assertEquals("Incorrect value from service registry", VALUE_THREE, registryService.getValue(KEY_A_B_C_D_3)); + + assertNull("Missing key should return null value", registryService.getValue("/a/b/c/0")); + assertNull("Missing key should return null value", registryService.getValue("/a/b/c/d/0")); + assertNull("Missing key should return null value", registryService.getValue("/x/y/z/0")); + } + + public void testSpecialCharacters() + { + registryService.addValue(KEY_SPECIAL, VALUE_THREE); + assertEquals("Incorrect value for special key", VALUE_THREE, registryService.getValue(KEY_SPECIAL)); + } +} diff --git a/source/java/org/alfresco/repo/rule/BaseRuleTest.java b/source/java/org/alfresco/repo/rule/BaseRuleTest.java index d15d1ea7d6..633fe48771 100644 --- a/source/java/org/alfresco/repo/rule/BaseRuleTest.java +++ b/source/java/org/alfresco/repo/rule/BaseRuleTest.java @@ -113,7 +113,7 @@ public class BaseRuleTest extends BaseSpringTest this.ruleService = (RuleService) this.applicationContext .getBean("ruleService"); this.configService = (ConfigurableService)this.applicationContext - .getBean("configurableService"); + .getBean("ConfigurableService"); this.actionService = (ActionService)this.applicationContext.getBean("actionService"); this.transactionService = (TransactionService)this.applicationContext.getBean("transactionComponent"); this.authenticationComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent");