From 0570c77f46cca7fedd1540ee6d7abbc6fb52e1fe Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Thu, 12 Apr 2007 02:02:42 +0000 Subject: [PATCH] Merged V2.0 to HEAD 5457: Merge error on copy web project action 5459: AR-1278 5461: 5462: A few deployment fixes 5469: Dictionary messages 5470: L2 cache checks 5478: WCM-374 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5485 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../messages/dictionary-messages.properties | 18 +- .../messages/patch-service.properties | 9 +- config/alfresco/model/contentModel.xml | 4 + .../alfresco/patch/patch-services-context.xml | 18 ++ source/java/ehcache.xml | 112 ------------ source/java/hibernate.cfg.xml | 40 ----- .../impl/InvalidUserPersonAndGroupPatch.java | 166 ++++++++++++++++++ .../avm/actions/AVMDeploySnapshotAction.java | 9 +- .../dictionary/M2ConstraintDefinition.java | 96 +++++----- .../constraint/AuthorityNameConstraint.java | 64 +++++++ .../constraint/UserNameConstraint.java | 69 ++++++++ .../repo/node/db/DbNodeServiceImpl.java | 27 +-- .../alfresco/repo/node/db/NodeDaoService.java | 7 + .../HibernateNodeDaoServiceImpl.java | 43 +++++ .../node/index/AbstractReindexComponent.java | 2 +- .../security/authentication/userModel.xml | 10 ++ 16 files changed, 473 insertions(+), 221 deletions(-) delete mode 100644 source/java/ehcache.xml delete mode 100644 source/java/hibernate.cfg.xml create mode 100644 source/java/org/alfresco/repo/admin/patch/impl/InvalidUserPersonAndGroupPatch.java create mode 100644 source/java/org/alfresco/repo/dictionary/constraint/AuthorityNameConstraint.java create mode 100644 source/java/org/alfresco/repo/dictionary/constraint/UserNameConstraint.java diff --git a/config/alfresco/messages/dictionary-messages.properties b/config/alfresco/messages/dictionary-messages.properties index f232cb6b60..7bbe0556bb 100644 --- a/config/alfresco/messages/dictionary-messages.properties +++ b/config/alfresco/messages/dictionary-messages.properties @@ -5,8 +5,8 @@ d_dictionary.model.err.type_not_found=Failed to create anonymous type as specifi d_dictionary.model.err.aspect_not_found=Failed to create anonymous type as specified aspect {0} not found d_dictionary.constraint.err.cyclic_ref=Constraint ''{0}'' is part of a cyclic reference of constraints -d_dictionary.constraint.err.type_and_ref=Constraint ''{0}'' cannot have a ''type'' and be a ''reference'' attribute -d_dictionary.constraint.err.type_or_ref=Constraint ''{0}'' cannot have a ''type'' and be a ''reference'' attribute +d_dictionary.constraint.err.type_and_ref=Constraint ''{0}'' cannot have a 'type' and be a 'reference' attribute +d_dictionary.constraint.err.type_or_ref=Constraint ''{0}'' cannot have a 'type' and be a 'reference' attribute d_dictionary.constraint.err.ref_not_found=Constraint reference ''{0}'' not found on constraint ''{1}'' d_dictionary.constraint.err.anon_needs_property=Anonymous constraints can only be declared within the context of a property d_dictionary.constraint.err.invalid_type=Constraint type ''{0}'' on constraint ''{1}'' is not a well-known type or a valid Constraint implementation @@ -26,16 +26,22 @@ d_dictionary.property.err.cannot_relax_mandatory_enforcement=Cannot relax mandat d_dictionary.constraint.regex.no_match=Value ''{0}'' does not match regular expression: {1} d_dictionary.constraint.regex.match=Value ''{0}'' matches regular expression: {1} -d_dictionary.constraint.numeric_range.invalid_min_value=Invalid ''minValue'' property: {0} -d_dictionary.constraint.numeric_range.invalid_max_value=Invalid ''maxValue'' property: {0} +d_dictionary.constraint.numeric_range.invalid_min_value=Invalid 'minValue' property: {0} +d_dictionary.constraint.numeric_range.invalid_max_value=Invalid 'maxValue' property: {0} d_dictionary.constraint.numeric_range.non_numeric=Property value could not be converted to a double: {0} d_dictionary.constraint.numeric_range.out_of_range=Numeric value ''{0}'' is not in range [{1}; {2}] -d_dictionary.constraint.string_length.invalid_min_length=Invalid ''minLength'' property: {0} -d_dictionary.constraint.string_length.invalid_max_length=Invalid ''maxLength'' property: {0} +d_dictionary.constraint.string_length.invalid_min_length=Invalid 'minLength' property: {0} +d_dictionary.constraint.string_length.invalid_max_length=Invalid 'maxLength' property: {0} d_dictionary.constraint.string_length.non_string=Property value could not be converted to a String: {0} d_dictionary.constraint.string_length.invalid_length=String length of ''{0}'' is not in range [{1}; {2}] d_dictionary.constraint.list_of_values.no_values=The list of allowed values is empty d_dictionary.constraint.list_of_values.non_string=Property value could not be converted to a String: {0} d_dictionary.constraint.list_of_values.invalid_value=The value is not an allowed value: {0} + +d_dictionary.constraint.user_name.invalid_user_name=The value ''{0}'' is not an allowed user name: it is an authority of type: {1} +d_dictionary.constraint.user_name.non_string=Property value could not be converted to a String: {0} + +d_dictionary.constraint.authority_name.invalid_authority_name=The value ''{0}'' is not an allowed authority name: it is an authority of type: {1} +d_dictionary.constraint.authority_name.non_string=Property value could not be converted to a String: {0} \ No newline at end of file diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index 5d58f903e1..ba961fc99f 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -137,7 +137,10 @@ patch.userAndPersonUserNamesAsIdentifiers.result=Reindexed user:user and cm:pers patch.contentFormFolderType.description=Update WCM Content Form folder type. patch.contentFormFolderType.result=Updated {0} WCM Content Form objects to 'wcm:formfolder' type. -patch.webscripts.description=Adds Web Scripts to Data Dictionary. - patch.groupNamesAsIdentifiers.description=Reindex usr:authorityContainer gids as identifiers -patch.groupNamesAsIdentifiers.result=Reindex usr:authorityContainer gids as identifiers \ No newline at end of file +patch.groupNamesAsIdentifiers.result=Reindex usr:authorityContainer gids as identifiers + +patch.invalidUserPersonAndGroup.description=Fix up invalid uids for people and users; and invalid gids for groups +patch.invalidUserPersonAndGroup.result=Fixed ''{0}'' invalid user nodes, ''{1}'' invalid person nodes and ''{2}'' invalid authority nodes. + +patch.webscripts.description=Adds Web Scripts to Data Dictionary. diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml index 4ce7ae1014..3dde8d3303 100644 --- a/config/alfresco/model/contentModel.xml +++ b/config/alfresco/model/contentModel.xml @@ -19,6 +19,7 @@ \<\?\/\:\|\xA3\xAC\%\&\+\;]+.*)|(.*[\.]?.*[\.]+$)|(.*[ ]+$)]]> false + @@ -147,6 +148,9 @@ d:text true + + + d:noderef diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 2f8cd053f9..9cf1d622e6 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -684,6 +684,24 @@ + + + patch.invalidUserPersonAndGroup + patch.invalidUserPersonAndGroup.description + 0 + 39 + 40 + + + + + + + + + + + patch.webscripts diff --git a/source/java/ehcache.xml b/source/java/ehcache.xml deleted file mode 100644 index 56f0d64f1c..0000000000 --- a/source/java/ehcache.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/java/hibernate.cfg.xml b/source/java/hibernate.cfg.xml deleted file mode 100644 index 9afbf2864f..0000000000 --- a/source/java/hibernate.cfg.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - root - - jdbc:mysql://127.0.0.1/avm - com.mysql.jdbc.Driver - thread - org.hibernate.dialect.MySQLInnoDBDialect - - false - false - 2 - - - 4 - 32 - 60 - 0 - 60 - - 16 - true - 15 - true - true - - - diff --git a/source/java/org/alfresco/repo/admin/patch/impl/InvalidUserPersonAndGroupPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/InvalidUserPersonAndGroupPatch.java new file mode 100644 index 0000000000..caf3c3a95c --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/impl/InvalidUserPersonAndGroupPatch.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ + +package org.alfresco.repo.admin.patch.impl; + +import java.io.Serializable; +import java.util.List; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.importer.ImporterBootstrap; +import org.alfresco.service.cmr.dictionary.ClassDefinition; +import org.alfresco.service.cmr.dictionary.ConstraintDefinition; +import org.alfresco.service.cmr.dictionary.ConstraintException; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.cmr.repository.datatype.TypeConversionException; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.ResultSetRow; +import org.alfresco.service.cmr.search.SearchParameters; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.namespace.QName; + +/** + * Patch usr:user and cm:person objects so that the user name properties are in the index in untokenized form. If not authentication may fail in mixed language use. + * + * @author andyh + */ +public class InvalidUserPersonAndGroupPatch extends AbstractPatch +{ + private static final String MSG_SUCCESS = "patch.invalidUserPersonAndGroup.result"; + + private ImporterBootstrap spacesImporterBootstrap; + + private ImporterBootstrap userImporterBootstrap; + + private DictionaryService dictionaryService; + + public InvalidUserPersonAndGroupPatch() + { + + } + + public void setSpacesImporterBootstrap(ImporterBootstrap spacesImporterBootstrap) + { + this.spacesImporterBootstrap = spacesImporterBootstrap; + } + + public void setUserImporterBootstrap(ImporterBootstrap userImporterBootstrap) + { + this.userImporterBootstrap = userImporterBootstrap; + } + + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + @Override + protected String applyInternal() throws Exception + { + int users = deleteInvalid(ContentModel.PROP_USER_USERNAME, userImporterBootstrap.getStoreRef(), "USER_"); + int people = deleteInvalid(ContentModel.PROP_USERNAME, spacesImporterBootstrap.getStoreRef(), "USER_"); + int authorities = deleteInvalid(ContentModel.PROP_AUTHORITY_NAME, userImporterBootstrap.getStoreRef(), "GROUP_"); + return I18NUtil.getMessage(MSG_SUCCESS, users, people, authorities); + } + + private int deleteInvalid(QName property, StoreRef store, String prefix) + { + PropertyDefinition propDef = dictionaryService.getProperty(property); + if (propDef == null) + { + return 0; + } + ClassDefinition typeDef = propDef.getContainerClass(); + + String query; + if (typeDef.isAspect()) + { + query = "ASPECT:\"" + typeDef.getName() + "\""; + } + else + { + query = "TYPE:\"" + typeDef.getName() + "\""; + } + + List conDefs = propDef.getConstraints(); + + SearchParameters sp = new SearchParameters(); + sp.setLanguage(SearchService.LANGUAGE_LUCENE); + sp.setQuery(query); + sp.addStore(store); + ResultSet rs = null; + int invalidCount = 0; + try + { + rs = searchService.query(sp); + for (ResultSetRow row : rs) + { + NodeRef nodeRef = row.getNodeRef(); + boolean valid = true; + Serializable value = nodeService.getProperty(nodeRef, property); + String checkValue = null; + try + { + checkValue = DefaultTypeConverter.INSTANCE.convert(String.class, value); + } + catch (TypeConversionException e) + { + continue; + } + + for (ConstraintDefinition con : conDefs) + { + try + { + con.getConstraint().evaluate(value); + } + catch (ConstraintException e) + { + valid = false; + } + } + if(!valid) + { + nodeService.setProperty(nodeRef, property, prefix+checkValue); + invalidCount++; + } + } + } + finally + { + if (rs != null) + { + rs.close(); + } + } + return invalidCount; + } +} diff --git a/source/java/org/alfresco/repo/avm/actions/AVMDeploySnapshotAction.java b/source/java/org/alfresco/repo/avm/actions/AVMDeploySnapshotAction.java index 3351bcf329..26b1e34d15 100644 --- a/source/java/org/alfresco/repo/avm/actions/AVMDeploySnapshotAction.java +++ b/source/java/org/alfresco/repo/avm/actions/AVMDeploySnapshotAction.java @@ -195,19 +195,21 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase DeploymentReport report = null; try { + String host = targetServer; int port = defaultRmiPort; // check whether there is a port number present, if so, use it int idx = targetServer.indexOf(":"); if (idx != -1) { + host = targetServer.substring(0, idx); String strPort = targetServer.substring(idx+1); port = Integer.parseInt(strPort); } // TODO: we need to capture username/password for the remote server at some - // point, for now we use the admin/admin account, need to externalise this too! - report = this.deployService.deployDifference(version, path, targetServer, port, + // point, for now we use the configured username/password for all servers + report = this.deployService.deployDifference(version, path, host, port, remoteUsername, remotePassword, targetPath, true, false, false, callback); } catch (Throwable err) @@ -247,8 +249,7 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase } // create the deployment report node - createDeploymentReportNode(report, (String)action.getParameterValue(PARAM_TARGET_SERVER), - version, websiteRef, startDate, deployError); + createDeploymentReportNode(report, targetServer, version, websiteRef, startDate, deployError); } /** diff --git a/source/java/org/alfresco/repo/dictionary/M2ConstraintDefinition.java b/source/java/org/alfresco/repo/dictionary/M2ConstraintDefinition.java index a0adc34147..c7920a9b92 100644 --- a/source/java/org/alfresco/repo/dictionary/M2ConstraintDefinition.java +++ b/source/java/org/alfresco/repo/dictionary/M2ConstraintDefinition.java @@ -46,40 +46,48 @@ import org.springframework.beans.PropertyAccessException; * * @author Derek Hulley */ -/*package*/ class M2ConstraintDefinition implements ConstraintDefinition +/* package */class M2ConstraintDefinition implements ConstraintDefinition { public static final String ERR_CYCLIC_REF = "d_dictionary.constraint.err.cyclic_ref"; + public static final String ERR_TYPE_AND_REF = "d_dictionary.constraint.err.type_and_ref"; + public static final String ERR_TYPE_OR_REF = "d_dictionary.constraint.err.type_or_ref"; + public static final String ERR_REF_NOT_FOUND = "d_dictionary.constraint.err.ref_not_found"; + public static final String ERR_ANON_NEEDS_PROPERTY = "d_dictionary.constraint.err.anon_needs_property"; + public static final String ERR_INVALID_TYPE = "d_dictionary.constraint.err.invalid_type"; + public static final String ERR_SIMPLE_AND_LIST = "d_dictionary.constraint.err.property_simple_and_list"; + public static final String ERR_CONSTRUCT_FAILURE = "d_dictionary.constraint.err.construct_failure"; + public static final String ERR_PROPERTY_MISMATCH = "d_dictionary.constraint.err.property_mismatch"; private static int anonPropCount = 0; - + private ModelDefinition model; + private NamespacePrefixResolver prefixResolver; + private M2Constraint m2Constraint; + private QName name; + private Constraint constraint; + private boolean resolving; - - /*package*/ M2ConstraintDefinition( - M2PropertyDefinition m2PropertyDef, - M2Constraint m2Constraint, + + /* package */M2ConstraintDefinition(M2PropertyDefinition m2PropertyDef, M2Constraint m2Constraint, NamespacePrefixResolver prefixResolver) { this(m2PropertyDef.getModel(), m2PropertyDef, m2Constraint, prefixResolver); } - - /*package*/ M2ConstraintDefinition( - ModelDefinition modelDefinition, - M2PropertyDefinition m2PropertyDef, - M2Constraint m2Constraint, - NamespacePrefixResolver prefixResolver) + + /* package */M2ConstraintDefinition(ModelDefinition modelDefinition, M2PropertyDefinition m2PropertyDef, + M2Constraint m2Constraint, NamespacePrefixResolver prefixResolver) { this.model = modelDefinition; this.m2Constraint = m2Constraint; @@ -103,8 +111,8 @@ import org.springframework.beans.PropertyAccessException; this.name = QName.createQName(m2Constraint.getName(), prefixResolver); } } - - /*package*/ synchronized void resolveDependencies(ModelQuery query) + + /* package */synchronized void resolveDependencies(ModelQuery query) { if (resolving) { @@ -121,7 +129,7 @@ import org.springframework.beans.PropertyAccessException; resolving = false; } } - + private synchronized void resolveInternal(ModelQuery query) { if (constraint != null) @@ -187,39 +195,43 @@ import org.springframework.beans.PropertyAccessException; // property setters BeanWrapper beanWrapper = new BeanWrapperImpl(constraint); List constraintNamedValues = m2Constraint.getParameters(); - for (M2NamedValue namedValue : constraintNamedValues) + + if (constraintNamedValues != null) { - Object value = null; - if (namedValue.getSimpleValue() != null && namedValue.getListValue() != null) + for (M2NamedValue namedValue : constraintNamedValues) { - throw new DictionaryException(ERR_SIMPLE_AND_LIST, shortName, namedValue.getName()); - } - else if (namedValue.getSimpleValue() != null) - { - value = namedValue.getSimpleValue(); - } - else if (namedValue.getListValue() != null) - { - value = namedValue.getListValue(); - } - try - { - beanWrapper.setPropertyValue(namedValue.getName(), value); - } - catch (PropertyAccessException e) - { - throw new DictionaryException(ERR_PROPERTY_MISMATCH, e, namedValue.getName(), shortName); - } - catch (InvalidPropertyException e) - { - throw new DictionaryException(ERR_PROPERTY_MISMATCH, e, namedValue.getName(), shortName); + Object value = null; + if (namedValue.getSimpleValue() != null && namedValue.getListValue() != null) + { + throw new DictionaryException(ERR_SIMPLE_AND_LIST, shortName, namedValue.getName()); + } + else if (namedValue.getSimpleValue() != null) + { + value = namedValue.getSimpleValue(); + } + else if (namedValue.getListValue() != null) + { + value = namedValue.getListValue(); + } + try + { + beanWrapper.setPropertyValue(namedValue.getName(), value); + } + catch (PropertyAccessException e) + { + throw new DictionaryException(ERR_PROPERTY_MISMATCH, e, namedValue.getName(), shortName); + } + catch (InvalidPropertyException e) + { + throw new DictionaryException(ERR_PROPERTY_MISMATCH, e, namedValue.getName(), shortName); + } } } // now initialize constraint.initialize(); } } - + /** * @see #getName() */ @@ -228,7 +240,7 @@ import org.springframework.beans.PropertyAccessException; { return getName().toString(); } - + public ModelDefinition getModel() { return model; @@ -243,7 +255,7 @@ import org.springframework.beans.PropertyAccessException; { return constraint; } - + /** * Well-known constraint types */ diff --git a/source/java/org/alfresco/repo/dictionary/constraint/AuthorityNameConstraint.java b/source/java/org/alfresco/repo/dictionary/constraint/AuthorityNameConstraint.java new file mode 100644 index 0000000000..bc5f33154d --- /dev/null +++ b/source/java/org/alfresco/repo/dictionary/constraint/AuthorityNameConstraint.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.repo.dictionary.constraint; + +import org.alfresco.service.cmr.dictionary.ConstraintException; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.cmr.repository.datatype.TypeConversionException; +import org.alfresco.service.cmr.security.AuthorityType; + +public class AuthorityNameConstraint extends AbstractConstraint +{ + + private static final String ERR_INVALID_AUTHORITY_NAME = "d_dictionary.constraint.authority_name.invalid_authority_name"; + private static final String ERR_NON_STRING = "d_dictionary.constraint.authority_name.non_string"; + + @Override + protected void evaluateSingleValue(Object value) + { + // ensure that the value can be converted to a String + String checkValue = null; + try + { + checkValue = DefaultTypeConverter.INSTANCE.convert(String.class, value); + } + catch (TypeConversionException e) + { + throw new ConstraintException(ERR_NON_STRING, value); + } + + AuthorityType type = AuthorityType.getAuthorityType(checkValue); + if((type != AuthorityType.GROUP) && (type != AuthorityType.ROLE)) + { + throw new ConstraintException(ERR_INVALID_AUTHORITY_NAME, value, type); + } + } + + public void initialize() + { + + } + +} diff --git a/source/java/org/alfresco/repo/dictionary/constraint/UserNameConstraint.java b/source/java/org/alfresco/repo/dictionary/constraint/UserNameConstraint.java new file mode 100644 index 0000000000..a5f2816158 --- /dev/null +++ b/source/java/org/alfresco/repo/dictionary/constraint/UserNameConstraint.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.repo.dictionary.constraint; + +import org.alfresco.service.cmr.dictionary.ConstraintException; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.cmr.repository.datatype.TypeConversionException; +import org.alfresco.service.cmr.security.AuthorityType; + +/** + * Apply constraints for user names. + * + * @author andyh + * + */ +public class UserNameConstraint extends AbstractConstraint +{ + private static final String ERR_INVALID_USERNAME = "d_dictionary.constraint.user_name.invalid_user_name"; + private static final String ERR_NON_STRING = "d_dictionary.constraint.user_name.non_string"; + + @Override + protected void evaluateSingleValue(Object value) + { + // ensure that the value can be converted to a String + String checkValue = null; + try + { + checkValue = DefaultTypeConverter.INSTANCE.convert(String.class, value); + } + catch (TypeConversionException e) + { + throw new ConstraintException(ERR_NON_STRING, value); + } + + AuthorityType type = AuthorityType.getAuthorityType(checkValue); + if((type != AuthorityType.USER) && (type != AuthorityType.GUEST)) + { + throw new ConstraintException(ERR_INVALID_USERNAME, value, type); + } + } + + public void initialize() + { + + } + +} diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index e0f1b8f138..da979030c1 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -314,8 +314,15 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // create the node instance Node childNode = nodeDaoService.newNode(store, newId, nodeTypeQName); - // get the parent node + // Get the parent node Node parentNode = getNodeNotNull(parentRef); + // Create the association + ChildAssoc childAssoc = nodeDaoService.newChildAssoc( + parentNode, + childNode, + true, + assocTypeQName, + assocQName); // Set the default property values addDefaultPropertyValues(nodeTypeDef, properties); @@ -331,13 +338,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl propertiesAfter = setPropertiesImpl(childNode, properties); } - // create the association - ChildAssoc childAssoc = nodeDaoService.newChildAssoc( - parentNode, - childNode, - true, - assocTypeQName, - assocQName); + // Ensure child uniqueness setChildUniqueName(childNode); // ensure uniqueness ChildAssociationRef childAssocRef = childAssoc.getChildAssocRef(); @@ -1069,7 +1070,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { Node node = getNodeNotNull(nodeRef); // get the assocs pointing to it - Collection parentAssocs = node.getParentAssocs(); + Collection parentAssocs = nodeDaoService.getParentAssocs(node); // list of results Collection results = new ArrayList(parentAssocs.size()); for (ChildAssoc assoc : parentAssocs) @@ -1089,7 +1090,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { Node node = getNodeNotNull(nodeRef); // get the assocs pointing to it - Collection parentAssocs = node.getParentAssocs(); + Collection parentAssocs = nodeDaoService.getParentAssocs(node); // shortcut if there are no assocs if (parentAssocs.size() == 0) { @@ -1319,7 +1320,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { NodeRef currentNodeRef = currentNode.getNodeRef(); // get the parent associations of the given node - Collection parentAssocs = currentNode.getParentAssocs(); + Collection parentAssocs = nodeDaoService.getParentAssocs(currentNode); // does the node have parents boolean hasParents = parentAssocs.size() > 0; // does the current node have a root aspect? @@ -1651,7 +1652,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } // parent associations ArrayList archivedParentAssocRefs = new ArrayList(5); - for (ChildAssoc assoc : node.getParentAssocs()) + for (ChildAssoc assoc : nodeDaoService.getParentAssocs(node)) { Long relatedNodeId = assoc.getParent().getId(); if (nodeStatusesById.containsKey(relatedNodeId)) @@ -1952,7 +1953,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl useName = (String) nameValue.getValue(DataTypeDefinition.TEXT); } // get all the parent assocs - Collection parentAssocs = childNode.getParentAssocs(); + Collection parentAssocs = nodeDaoService.getParentAssocs(childNode); for (ChildAssoc assoc : parentAssocs) { QName assocTypeQName = assoc.getTypeQName(); diff --git a/source/java/org/alfresco/repo/node/db/NodeDaoService.java b/source/java/org/alfresco/repo/node/db/NodeDaoService.java index de21852986..45ec879e45 100644 --- a/source/java/org/alfresco/repo/node/db/NodeDaoService.java +++ b/source/java/org/alfresco/repo/node/db/NodeDaoService.java @@ -223,6 +223,13 @@ public interface NodeDaoService */ public ChildAssoc getPrimaryParentAssoc(Node node); + /** + * Get all parent associations for the node. This methods includes a cache safety check. + * @param node the child node + * @return Returns all parent associations for the node. + */ + public Collection getParentAssocs(Node node); + /** * @return Returns the persisted and filled association * @see NodeAssoc diff --git a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java index 65a2347c54..fb0989efb8 100644 --- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java @@ -900,6 +900,49 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements getSession().flush(); } + /** + * @inheritDoc + * + * This method includes a check to ensure that the parentAssocs cache + * isn't incorrectly empty. + */ + public Collection getParentAssocs(Node node) + { + Collection parentAssocs = node.getParentAssocs(); + if (parentAssocs.size() == 0) + { + // the only condition where this is allowed is if the given node is a root node + Store store = node.getStore(); + Node rootNode = store.getRootNode(); + if (rootNode == null) + { + // a store without a root node - the entire store is hosed + throw new DataIntegrityViolationException("Store has no root node: \n" + + " store: " + store); + } + if (!rootNode.equals(node)) + { + // Reload the node to ensure that it is properly initialized + getSession().refresh(node); + // Check if it has any parents yet. + if (node.getParentAssocs().size() == 0) + { + // It wasn't the root node and definitely has no parent + throw new DataIntegrityViolationException( + "Non-root node has no primary parent: \n" + + " child: " + node); + } + else + { + // Repeat this method with confidence + return getParentAssocs(node); + } + } + } + // Done + return parentAssocs; + } + private Set warnedDuplicateParents = new HashSet(3); /** * @inheritDoc diff --git a/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java index 41321fe171..732ddb9926 100644 --- a/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java +++ b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java @@ -68,7 +68,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery private static Log logger = LogFactory.getLog(AbstractReindexComponent.class); /** kept to notify the thread that it should quit */ - private static VmShutdownListener vmShutdownListener = new VmShutdownListener("MissingContentReindexComponent"); + private static VmShutdownListener vmShutdownListener = new VmShutdownListener("IndexRecovery"); private AuthenticationComponent authenticationComponent; /** provides transactions to atomically index each missed transaction */ diff --git a/source/java/org/alfresco/repo/security/authentication/userModel.xml b/source/java/org/alfresco/repo/security/authentication/userModel.xml index 3818aef28a..ce732b07c2 100644 --- a/source/java/org/alfresco/repo/security/authentication/userModel.xml +++ b/source/java/org/alfresco/repo/security/authentication/userModel.xml @@ -14,6 +14,10 @@ + + + + @@ -30,6 +34,9 @@ d:text + + + d:text @@ -66,6 +73,9 @@ d:text + + + d:text