diff --git a/config/alfresco/attributes-service-context.xml b/config/alfresco/attributes-service-context.xml index 8cef62442e..4d468fa4c6 100644 --- a/config/alfresco/attributes-service-context.xml +++ b/config/alfresco/attributes-service-context.xml @@ -33,7 +33,18 @@ - + + + + + + + daoServiceDirtySessionInterceptor + + + + + @@ -45,7 +56,18 @@ - + + + + + + + daoServiceDirtySessionInterceptor + + + + + @@ -54,13 +76,35 @@ - + + + + + + + daoServiceDirtySessionInterceptor + + + + + - + + + + + + + daoServiceDirtySessionInterceptor + + + + + diff --git a/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.1.sql b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.1.sql index 2a8742f046..cf1f89092a 100644 --- a/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.1.sql +++ b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.1.sql @@ -40,54 +40,6 @@ CREATE TABLE alf_qname UNIQUE (ns_id, local_name) ) ENGINE=InnoDB; --- Create temporary table for dynamic (child) QNames -CREATE TABLE t_qnames_dyn -( - qname VARCHAR(255) NOT NULL, - namespace VARCHAR(100), - namespace_id BIGINT, - local_name VARCHAR(200), - INDEX tidx_qnd_qn (qname), - INDEX tidx_qnd_ns (namespace) -) ENGINE=InnoDB; - --- Populate the table with the child association paths --- Query OK, 415312 rows affected (1 min 11.91 sec) -INSERT INTO t_qnames_dyn (qname) -( - SELECT distinct(qname) FROM alf_child_assoc -); - --- Extract the Namespace --- Query OK, 415312 rows affected (20.03 sec) -UPDATE t_qnames_dyn SET namespace = CONCAT('FILLER-', SUBSTR(SUBSTRING_INDEX(qname, '}', 1), 2)); - --- Extract the Localname --- Query OK, 415312 rows affected (16.22 sec) -UPDATE t_qnames_dyn SET local_name = SUBSTRING_INDEX(qname, '}', -1); - --- Move the namespaces to the their new home --- Query OK, 4 rows affected (34.59 sec) -INSERT INTO alf_namespace (uri, version) -( - SELECT - distinct(x.namespace), 1 - FROM - ( - SELECT t.namespace, n.uri FROM t_qnames_dyn t LEFT OUTER JOIN alf_namespace n ON (n.uri = t.namespace) - ) x - WHERE - x.uri IS NULL -); - --- Record the new namespace IDs --- Query OK, 415312 rows affected (10.41 sec) -UPDATE t_qnames_dyn t SET t.namespace_id = (SELECT ns.id FROM alf_namespace ns WHERE ns.uri = t.namespace); - --- Recoup some storage -ALTER TABLE t_qnames_dyn DROP COLUMN namespace; -OPTIMIZE TABLE t_qnames_dyn; - -- Create temporary table to hold static QNames CREATE TABLE t_qnames ( @@ -188,6 +140,62 @@ UPDATE t_qnames t SET t.qname_id = WHERE ns.uri = t.namespace AND q.local_name = t.localname ); +-- ---------------------------- +-- SHORTCUT: +-- Up to this point, we have been extracting static data. The data can be dumped and loaded +-- to do faster testing of the ugprades: +-- mysqldump derek1 alf_qname alf_namespace t_qnames > extracted-qnames.sql +-- Load the dump file and continue from this point +-- ---------------------------- + +-- Create temporary table for dynamic (child) QNames +CREATE TABLE t_qnames_dyn +( + qname VARCHAR(255) NOT NULL, + namespace VARCHAR(100), + namespace_id BIGINT, + local_name VARCHAR(200), + INDEX tidx_qnd_qn (qname), + INDEX tidx_qnd_ns (namespace) +) ENGINE=InnoDB; + +-- Populate the table with the child association paths +-- Query OK, 415312 rows affected (1 min 11.91 sec) +INSERT INTO t_qnames_dyn (qname) +( + SELECT distinct(qname) FROM alf_child_assoc +); + +-- Extract the Namespace +-- Query OK, 415312 rows affected (20.03 sec) +UPDATE t_qnames_dyn SET namespace = CONCAT('FILLER-', SUBSTR(SUBSTRING_INDEX(qname, '}', 1), 2)); + +-- Extract the Localname +-- Query OK, 415312 rows affected (16.22 sec) +UPDATE t_qnames_dyn SET local_name = SUBSTRING_INDEX(qname, '}', -1); + +-- Move the namespaces to the their new home +-- Query OK, 4 rows affected (34.59 sec) +INSERT INTO alf_namespace (uri, version) +( + SELECT + distinct(x.namespace), 1 + FROM + ( + SELECT t.namespace, n.uri FROM t_qnames_dyn t LEFT OUTER JOIN alf_namespace n ON (n.uri = t.namespace) + ) x + WHERE + x.uri IS NULL +); + +-- Record the new namespace IDs +-- Query OK, 415312 rows affected (10.41 sec) +UPDATE t_qnames_dyn t SET t.namespace_id = (SELECT ns.id FROM alf_namespace ns WHERE ns.uri = t.namespace); + +-- Recoup some storage +ALTER TABLE t_qnames_dyn DROP COLUMN namespace; +OPTIMIZE TABLE t_qnames_dyn; + -- ---------------------------- -- Populate the Permissions -- -- ---------------------------- @@ -263,24 +271,40 @@ INSERT INTO t_alf_store (version, protocol, identifier, root_node_id) SELECT 1, protocol, identifier, root_node_id FROM alf_store ; --- Add type_qname index for nodes -CREATE INDEX tidx_node_tqn ON alf_node (type_qname); +-- Summarize the alf_node_status table +CREATE TABLE t_summary_nstat +( + node_id BIGINT(20) NOT NULL, + transaction_id BIGINT(20) DEFAULT NULL, + PRIMARY KEY (node_id) +) TYPE=InnoDB; +INSERT INTO t_summary_nstat (node_id, transaction_id) + SELECT node_id, transaction_id FROM alf_node_status WHERE node_id IS NOT NULL; -- Copy data over +LOCK TABLES + t_alf_node WRITE, + alf_node AS n READ, + t_summary_nstat AS nstat READ, + t_alf_store AS s READ, + t_qnames AS q READ +; INSERT INTO t_alf_node ( id, version, store_id, uuid, transaction_id, node_deleted, type_qname_id, acl_id, - audit_creator, audit_created, audit_modifier, audit_modified + audit_creator, audit_created, audit_modifier, audit_modified, audit_accessed ) - SELECT + SELECT STRAIGHT_JOIN n.id, 1, s.id, n.uuid, nstat.transaction_id, false, q.qname_id, n.acl_id, - null, null, null, null + null, null, null, null, null FROM alf_node n JOIN t_qnames q ON (q.qname = n.type_qname) - JOIN alf_node_status nstat ON (nstat.node_id = n.id) - JOIN t_alf_store s ON (s.protocol = nstat.protocol AND s.identifier = nstat.identifier) + JOIN t_summary_nstat nstat ON (nstat.node_id = n.id) + JOIN t_alf_store s ON (s.protocol = n.protocol AND s.identifier = n.identifier) ; +UNLOCK TABLES; +DROP TABLE t_summary_nstat; -- Hook the store up to the root node ALTER TABLE t_alf_store @@ -327,8 +351,8 @@ CREATE TABLE t_alf_child_assoc version BIGINT NOT NULL, parent_node_id BIGINT NOT NULL, type_qname_id BIGINT NOT NULL, - child_node_name VARCHAR(50) NOT NULL, child_node_name_crc BIGINT NOT NULL, + child_node_name VARCHAR(50) NOT NULL, child_node_id BIGINT NOT NULL, qname_ns_id BIGINT NOT NULL, qname_localname VARCHAR(100) NOT NULL, @@ -344,24 +368,31 @@ CREATE TABLE t_alf_child_assoc CONSTRAINT fk_alf_cass_tqn foreign key (type_qname_id) REFERENCES alf_qname (id), CONSTRAINT fk_alf_cass_qnns foreign key (qname_ns_id) REFERENCES alf_namespace (id), PRIMARY KEY (id), - UNIQUE (parent_node_id, type_qname_id, child_node_name, child_node_name_crc) + UNIQUE (parent_node_id, type_qname_id, child_node_name_crc, child_node_name) ) TYPE=InnoDB; --- Query OK, 830217 rows affected (11 min 59.10 sec) +LOCK TABLES + t_alf_child_assoc WRITE, + alf_child_assoc AS ca READ, + t_qnames_dyn AS tqndyn READ, + t_qnames AS tqn READ +; INSERT INTO t_alf_child_assoc ( id, version, - parent_node_id, child_node_id, - child_node_name, child_node_name_crc, + parent_node_id, type_qname_id, + child_node_name_crc, child_node_name, + child_node_id, qname_ns_id, qname_localname, is_primary, assoc_index ) - SELECT + SELECT STRAIGHT_JOIN ca.id, 1, - ca.parent_node_id, ca.child_node_id, - ca.child_node_name, child_node_name_crc, + ca.parent_node_id, tqn.qname_id, + ca.child_node_name_crc, ca.child_node_name, + ca.child_node_id, tqndyn.namespace_id, tqndyn.local_name, ca.is_primary, ca.assoc_index FROM @@ -369,6 +400,7 @@ INSERT INTO t_alf_child_assoc JOIN t_qnames_dyn tqndyn ON (ca.qname = tqndyn.qname) JOIN t_qnames tqn ON (ca.type_qname = tqn.qname) ; +UNLOCK TABLES; -- Clean up DROP TABLE t_qnames_dyn; @@ -396,20 +428,26 @@ CREATE TABLE t_alf_node_assoc UNIQUE (source_node_id, target_node_id, type_qname_id) ) TYPE=InnoDB; +LOCK TABLES + t_alf_node_assoc WRITE, + alf_node_assoc AS na READ, + t_qnames AS tqn READ +; INSERT INTO t_alf_node_assoc ( id, version, source_node_id, target_node_id, type_qname_id ) - SELECT + SELECT STRAIGHT_JOIN na.id, 1, - na.source_node_id, na.source_node_id, + na.source_node_id, na.target_node_id, tqn.qname_id FROM alf_node_assoc na JOIN t_qnames tqn ON (na.type_qname = tqn.qname) ; +UNLOCK TABLES; -- Clean up DROP TABLE alf_node_assoc; @@ -463,8 +501,12 @@ CREATE TABLE t_alf_node_aspects PRIMARY KEY (node_id, qname_id) ) TYPE=InnoDB; +LOCK TABLES + t_alf_node_aspects WRITE, + alf_node_aspects AS na READ, + t_qnames AS tqn READ +; -- Note the omission of sys:referencable. This is implicit. --- Query OK, 415051 rows affected (17.59 sec) INSERT INTO t_alf_node_aspects ( node_id, qname_id @@ -476,11 +518,9 @@ INSERT INTO t_alf_node_aspects alf_node_aspects na JOIN t_qnames tqn ON (na.qname = tqn.qname) WHERE - tqn.qname NOT IN - ( - '{http://www.alfresco.org/model/system/1.0}referenceable' - ) + tqn.qname != '{http://www.alfresco.org/model/system/1.0}referenceable' ; +UNLOCK TABLES; -- Clean up DROP TABLE alf_node_aspects; @@ -609,6 +649,7 @@ ALTER TABLE t_avm_store_properties RENAME TO avm_store_properties; CREATE TABLE t_avm_node_properties ( node_id BIGINT NOT NULL, + qname_id BIGINT NOT NULL, actual_type_n INTEGER NOT NULL, persisted_type_n INTEGER NOT NULL, multi_valued BIT NOT NULL, @@ -618,7 +659,6 @@ CREATE TABLE t_avm_node_properties double_value DOUBLE PRECISION, string_value TEXT, serializable_value BLOB, - qname_id BIGINT NOT NULL, INDEX fk_avm_nprop_n (node_id), INDEX fk_avm_nprop_qn (qname_id), CONSTRAINT fk_avm_nprop_n FOREIGN KEY (node_id) REFERENCES avm_nodes (id), @@ -722,16 +762,23 @@ CREATE TABLE t_alf_node_properties ) TYPE=InnoDB; -- Copy values over +LOCK TABLES + t_alf_node_properties WRITE, + alf_node_properties AS np READ, + t_prop_types AS ptypes_actual READ, + t_prop_types AS ptypes_persisted READ, + t_qnames AS tqn READ +; INSERT INTO t_alf_node_properties ( - node_id, qname_id, list_index, locale_id, + node_id, qname_id, locale_id, list_index, actual_type_n, persisted_type_n, boolean_value, long_value, float_value, double_value, string_value, serializable_value ) SELECT - np.node_id, tqn.qname_id, -1, 1, + np.node_id, tqn.qname_id, 1, -1, ptypes_actual.type_id, ptypes_persisted.type_id, np.boolean_value, np.long_value, np.float_value, np.double_value, np.string_value, @@ -744,6 +791,7 @@ INSERT INTO t_alf_node_properties WHERE np.attribute_value IS NULL ; +UNLOCK TABLES; -- Update cm:auditable properties on the nodes UPDATE t_alf_node n SET audit_creator = ( @@ -798,6 +846,19 @@ UPDATE t_alf_node n SET audit_modified = qn.local_name = 'modified' ); -- Remove the unused cm:auditable properties +-- SHORTCUT: +-- The qname_id values can be determined up front +-- SELECT * FROM +-- alf_qname +-- JOIN alf_namespace ON (alf_qname.ns_id = alf_namespace.id) +-- WHERE +-- alf_namespace.uri = 'FILLER-http://www.alfresco.org/model/content/1.0' AND +-- alf_qname.local_name IN ('creator', 'created', 'modifier', 'modified') +-- ; +-- DELETE t_alf_node_properties +-- FROM t_alf_node_properties +-- WHERE +-- qname_id IN (13, 14, 23, 24); DELETE t_alf_node_properties FROM t_alf_node_properties JOIN alf_qname ON (t_alf_node_properties.qname_id = alf_qname.id) @@ -810,14 +871,14 @@ DELETE t_alf_node_properties -- Copy all MLText values over INSERT INTO t_alf_node_properties ( - node_id, qname_id, list_index, locale_id, + node_id, qname_id, locale_id, list_index, actual_type_n, persisted_type_n, boolean_value, long_value, float_value, double_value, string_value, serializable_value ) SELECT - np.node_id, tqn.qname_id, -1, loc.id, + np.node_id, tqn.qname_id, loc.id, -1, -1, 0, FALSE, 0, 0, 0, a2.string_value, @@ -838,6 +899,7 @@ UPDATE t_alf_node_properties SET actual_type_n = 9, persisted_type_n = 9 WHERE actual_type_n = -1 AND serializable_value IS NOT NULL ; +DELETE FROM t_alf_node_properties WHERE actual_type_n = -1; -- Delete the node properties and move the fixed values over DROP TABLE alf_node_properties; diff --git a/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.2SP1.sql b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.2SP1.sql index b4cfbb5bd7..089a51c6db 100644 --- a/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.2SP1.sql +++ b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/upgrade-from-2.2SP1.sql @@ -63,20 +63,38 @@ INSERT INTO t_alf_store (version, protocol, identifier, root_node_id) SELECT 1, protocol, identifier, root_node_id FROM alf_store ; +-- Summarize the alf_node_status table +CREATE TABLE t_summary_nstat +( + node_id BIGINT(20) NOT NULL, + transaction_id BIGINT(20) DEFAULT NULL, + PRIMARY KEY (node_id) +) TYPE=InnoDB; +INSERT INTO t_summary_nstat (node_id, transaction_id) + SELECT node_id, transaction_id FROM alf_node_status WHERE node_id IS NOT NULL; + -- Copy data over +LOCK TABLES + t_alf_node WRITE, + alf_node AS n READ, + t_summary_nstat AS nstat READ, + t_alf_store AS s READ +; INSERT INTO t_alf_node ( id, version, store_id, uuid, transaction_id, node_deleted, type_qname_id, acl_id, - audit_creator, audit_created, audit_modifier, audit_modified + audit_creator, audit_created, audit_modifier, audit_modified, audit_accessed ) - SELECT + SELECT STRAIGHT_JOIN n.id, 1, s.id, n.uuid, nstat.transaction_id, false, n.type_qname_id, n.acl_id, - null, null, null, null + null, null, null, null, null FROM alf_node n - JOIN alf_node_status nstat ON (nstat.node_id = n.id) - JOIN t_alf_store s ON (s.protocol = nstat.protocol AND s.identifier = nstat.identifier) + JOIN t_summary_nstat nstat ON (nstat.node_id = n.id) + JOIN t_alf_store s ON (s.protocol = n.protocol AND s.identifier = n.identifier) ; +UNLOCK TABLES; +DROP TABLE t_summary_nstat; -- Hook the store up to the root node ALTER TABLE t_alf_store @@ -123,8 +141,8 @@ CREATE TABLE t_alf_child_assoc version BIGINT NOT NULL, parent_node_id BIGINT NOT NULL, type_qname_id BIGINT NOT NULL, - child_node_name VARCHAR(50) NOT NULL, child_node_name_crc BIGINT NOT NULL, + child_node_name VARCHAR(50) NOT NULL, child_node_id BIGINT NOT NULL, qname_ns_id BIGINT NOT NULL, qname_localname VARCHAR(100) NOT NULL, @@ -140,28 +158,35 @@ CREATE TABLE t_alf_child_assoc CONSTRAINT fk_alf_cass_tqn foreign key (type_qname_id) REFERENCES alf_qname (id), CONSTRAINT fk_alf_cass_qnns foreign key (qname_ns_id) REFERENCES alf_namespace (id), PRIMARY KEY (id), - UNIQUE (parent_node_id, type_qname_id, child_node_name, child_node_name_crc) + UNIQUE (parent_node_id, type_qname_id, child_node_name_crc, child_node_name) ) TYPE=InnoDB; +LOCK TABLES + t_alf_child_assoc WRITE, + alf_child_assoc AS ca READ +; INSERT INTO t_alf_child_assoc ( id, version, - parent_node_id, child_node_id, - child_node_name, child_node_name_crc, + parent_node_id, type_qname_id, + child_node_name_crc, child_node_name, + child_node_id, qname_ns_id, qname_localname, is_primary, assoc_index ) - SELECT + SELECT STRAIGHT_JOIN ca.id, 1, - ca.parent_node_id, ca.child_node_id, - ca.child_node_name, child_node_name_crc, + ca.parent_node_id, ca.type_qname_id, + ca.child_node_name_crc, ca.child_node_name, + ca.child_node_id, ca.qname_ns_id, ca.qname_localname, ca.is_primary, ca.assoc_index FROM alf_child_assoc ca ; +UNLOCK TABLES; -- Clean up DROP TABLE alf_child_assoc; @@ -188,19 +213,24 @@ CREATE TABLE t_alf_node_assoc UNIQUE (source_node_id, target_node_id, type_qname_id) ) TYPE=InnoDB; +LOCK TABLES + t_alf_node_assoc WRITE, + alf_node_assoc AS na READ +; INSERT INTO t_alf_node_assoc ( id, version, source_node_id, target_node_id, type_qname_id ) - SELECT + SELECT STRAIGHT_JOIN na.id, 1, - na.source_node_id, na.source_node_id, + na.source_node_id, na.target_node_id, na.type_qname_id FROM alf_node_assoc na ; +UNLOCK TABLES; -- Clean up DROP TABLE alf_node_assoc; @@ -254,6 +284,12 @@ CREATE TABLE t_alf_node_aspects PRIMARY KEY (node_id, qname_id) ) TYPE=InnoDB; +LOCK TABLES + t_alf_node_aspects WRITE, + alf_node_aspects AS na READ, + alf_qname AS qn READ, + alf_namespace AS ns READ +; -- Note the omission of sys:referencable. This is implicit. INSERT INTO t_alf_node_aspects ( @@ -270,6 +306,7 @@ INSERT INTO t_alf_node_aspects ns.uri != 'http://www.alfresco.org/model/system/1.0' OR qn.local_name != 'referenceable' ; +UNLOCK TABLES; -- Clean up DROP TABLE alf_node_aspects; @@ -353,6 +390,7 @@ ALTER TABLE t_avm_store_properties RENAME TO avm_store_properties; CREATE TABLE t_avm_node_properties ( node_id BIGINT NOT NULL, + qname_id BIGINT NOT NULL, actual_type_n INTEGER NOT NULL, persisted_type_n INTEGER NOT NULL, multi_valued BIT NOT NULL, @@ -362,7 +400,6 @@ CREATE TABLE t_avm_node_properties double_value DOUBLE PRECISION, string_value TEXT, serializable_value BLOB, - qname_id BIGINT NOT NULL, INDEX fk_avm_nprop_n (node_id), INDEX fk_avm_nprop_qn (qname_id), CONSTRAINT fk_avm_nprop_n FOREIGN KEY (node_id) REFERENCES avm_nodes (id), @@ -441,16 +478,20 @@ CREATE TABLE t_alf_node_properties ) TYPE=InnoDB; -- Copy values over +LOCK TABLES + t_alf_node_properties WRITE, + alf_node_properties AS np READ +; INSERT INTO t_alf_node_properties ( - node_id, qname_id, list_index, locale_id, + node_id, qname_id, locale_id, list_index, actual_type_n, persisted_type_n, boolean_value, long_value, float_value, double_value, string_value, serializable_value ) SELECT - np.node_id, np.qname_id, -1, 1, + np.node_id, np.qname_id, 1, -1, np.actual_type_n, np.persisted_type_n, np.boolean_value, np.long_value, np.float_value, np.double_value, np.string_value, @@ -460,6 +501,7 @@ INSERT INTO t_alf_node_properties WHERE np.attribute_value IS NULL ; +UNLOCK TABLES; -- Update cm:auditable properties on the nodes UPDATE t_alf_node n SET audit_creator = ( @@ -553,6 +595,7 @@ UPDATE t_alf_node_properties SET actual_type_n = 9, persisted_type_n = 9 WHERE actual_type_n = -1 AND serializable_value IS NOT NULL ; +DELETE FROM t_alf_node_properties WHERE actual_type_n = -1; -- Delete the node properties and move the fixed values over DROP TABLE alf_node_properties; diff --git a/config/alfresco/ehcache-default.xml b/config/alfresco/ehcache-default.xml index 31d0627fee..2f4cde0a7d 100644 --- a/config/alfresco/ehcache-default.xml +++ b/config/alfresco/ehcache-default.xml @@ -282,6 +282,24 @@ timeToLiveSeconds="300" overflowToDisk="false" /> + + + + + + + + + + + + + + + + + + - + + diff --git a/config/alfresco/public-services-context.xml b/config/alfresco/public-services-context.xml index aa4b89b1fa..457b0ff937 100644 --- a/config/alfresco/public-services-context.xml +++ b/config/alfresco/public-services-context.xml @@ -833,6 +833,7 @@ avmSessionSizeResourceInterceptor + checkTxnAdvisor diff --git a/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java index f85c7a1a26..12522f3f65 100644 --- a/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/ImageTransformActionExecuter.java @@ -35,6 +35,7 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NoTransformerException; +import org.alfresco.service.cmr.repository.NodeRef; /** * Transfor action executer @@ -74,7 +75,9 @@ public class ImageTransformActionExecuter extends TransformActionExecuter /** * @see org.alfresco.repo.action.executer.TransformActionExecuter#doTransform(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter) */ - protected void doTransform(Action ruleAction, ContentReader contentReader, ContentWriter contentWriter) + protected void doTransform( Action ruleAction, + NodeRef sourceNodeRef, ContentReader contentReader, + NodeRef destinationNodeRef, ContentWriter contentWriter) { // check if the transformer is going to work, i.e. is available if (!this.imageMagickContentTransformer.isAvailable()) diff --git a/source/java/org/alfresco/repo/attributes/AttributeDAO.java b/source/java/org/alfresco/repo/attributes/AttributeDAO.java index 5f69b355e7..a3fae0bcf2 100644 --- a/source/java/org/alfresco/repo/attributes/AttributeDAO.java +++ b/source/java/org/alfresco/repo/attributes/AttributeDAO.java @@ -27,6 +27,7 @@ package org.alfresco.repo.attributes; import java.util.List; +import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; import org.alfresco.service.cmr.attributes.AttrQuery; import org.alfresco.util.Pair; @@ -40,12 +41,14 @@ public interface AttributeDAO * Save an attribute (recursively). * @param attr The attribute to save. */ + @DirtySessionAnnotation(markDirty=true) public void save(Attribute attr); /** * Delete an attribute (recursively). * @param attr The attribute to delete. */ + @DirtySessionAnnotation(markDirty=true) public void delete(Attribute attr); /** @@ -54,6 +57,7 @@ public interface AttributeDAO * @param query The AttrQuery. * @return A List of key, attribute value pairs. */ + @DirtySessionAnnotation(markDirty=false) public List> find(MapAttribute map, AttrQuery query); /** @@ -61,22 +65,26 @@ public interface AttributeDAO * @param map * @param query */ + @DirtySessionAnnotation(markDirty=true) public void delete(MapAttribute map, AttrQuery query); /** * Evict an Attribute from the session cache. * @param attr */ + @DirtySessionAnnotation(markDirty=false) public void evict(Attribute attr); /** * Evict an Attribute non-recursively. * @param attr */ + @DirtySessionAnnotation(markDirty=false) public void evictFlat(Attribute attr); /** * Force a flush. */ + @DirtySessionAnnotation(markDirty=false) public void flush(); } diff --git a/source/java/org/alfresco/repo/attributes/GlobalAttributeEntryDAO.java b/source/java/org/alfresco/repo/attributes/GlobalAttributeEntryDAO.java index 5919735691..5ca28cc03b 100644 --- a/source/java/org/alfresco/repo/attributes/GlobalAttributeEntryDAO.java +++ b/source/java/org/alfresco/repo/attributes/GlobalAttributeEntryDAO.java @@ -2,6 +2,8 @@ package org.alfresco.repo.attributes; import java.util.List; +import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; + /** * Interface for persistence of the top level attribute map. * @author britt @@ -12,18 +14,21 @@ public interface GlobalAttributeEntryDAO * Save an entry. * @param entry To save. */ + @DirtySessionAnnotation(markDirty=true) public void save(GlobalAttributeEntry entry); /** * Delete an entry. * @param entry To delete. */ + @DirtySessionAnnotation(markDirty=true) public void delete(GlobalAttributeEntry entry); /** * Delete an entry by name. * @param name The name of the entry. */ + @DirtySessionAnnotation(markDirty=true) public void delete(String name); /** @@ -31,11 +36,13 @@ public interface GlobalAttributeEntryDAO * @param name The name of the attribute. * @return The entry or null. */ + @DirtySessionAnnotation(markDirty=false) public GlobalAttributeEntry get(String name); /** * Get all keys for global attributes. * @return A list of all top level keys. */ + @DirtySessionAnnotation(markDirty=false) public List getKeys(); } diff --git a/source/java/org/alfresco/repo/attributes/ListEntryDAO.java b/source/java/org/alfresco/repo/attributes/ListEntryDAO.java index fc52814d8e..4a475c23df 100644 --- a/source/java/org/alfresco/repo/attributes/ListEntryDAO.java +++ b/source/java/org/alfresco/repo/attributes/ListEntryDAO.java @@ -27,6 +27,8 @@ package org.alfresco.repo.attributes; import java.util.List; +import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; + /** * DAO interface for ListEntries. * @author britt @@ -37,6 +39,7 @@ public interface ListEntryDAO * Save a new Entry. * @param entry */ + @DirtySessionAnnotation(markDirty=true) public void save(ListEntry entry); /** @@ -45,6 +48,7 @@ public interface ListEntryDAO * @param index The index. * @return The ListEntry. */ + @DirtySessionAnnotation(markDirty=false) public ListEntry get(ListEntryKey key); /** @@ -52,18 +56,21 @@ public interface ListEntryDAO * @param list The ListAttribute. * @return The entries. */ + @DirtySessionAnnotation(markDirty=false) public List get(ListAttribute list); /** * Delete a list entry. * @param entry */ + @DirtySessionAnnotation(markDirty=true) public void delete(ListEntry entry); /** * Delete all entries from a list. * @param list */ + @DirtySessionAnnotation(markDirty=true) public void delete(ListAttribute list); /** @@ -71,5 +78,6 @@ public interface ListEntryDAO * @param list The list. * @return The count of entries. */ + @DirtySessionAnnotation(markDirty=false) public int size(ListAttribute list); } diff --git a/source/java/org/alfresco/repo/attributes/MapEntryDAO.java b/source/java/org/alfresco/repo/attributes/MapEntryDAO.java index 53ba99ec9a..bdc0bd2e20 100644 --- a/source/java/org/alfresco/repo/attributes/MapEntryDAO.java +++ b/source/java/org/alfresco/repo/attributes/MapEntryDAO.java @@ -2,6 +2,8 @@ package org.alfresco.repo.attributes; import java.util.List; +import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; + /** * Interface for MapEntry persistence. * @author britt @@ -12,18 +14,21 @@ public interface MapEntryDAO * Save a MapEntry. * @param entry To save. */ + @DirtySessionAnnotation(markDirty=true) public void save(MapEntry entry); /** * Delete a MapEntry. * @param entry */ + @DirtySessionAnnotation(markDirty=true) public void delete(MapEntry entry); /** * Delete all entries for a map. * @param mapAttr The map to purge. */ + @DirtySessionAnnotation(markDirty=true) public void delete(MapAttribute mapAttr); /** @@ -31,6 +36,7 @@ public interface MapEntryDAO * @param key The key of the entry. * @return A MapEntry or null. */ + @DirtySessionAnnotation(markDirty=false) public MapEntry get(MapEntryKey key); /** @@ -38,6 +44,7 @@ public interface MapEntryDAO * @param mapAttr * @return A List of all entries in the given map. */ + @DirtySessionAnnotation(markDirty=false) public List get(MapAttribute mapAttr); /** @@ -45,11 +52,13 @@ public interface MapEntryDAO * @param mapAttr The MapAttribute/ * @return The number of entries. */ + @DirtySessionAnnotation(markDirty=false) public int size(MapAttribute mapAttr); /** * Evict an entry. * @param entry */ + @DirtySessionAnnotation(markDirty=false) public void evict(MapEntry entry); } diff --git a/source/java/org/alfresco/repo/attributes/hibernate/AttributeDAOHibernate.java b/source/java/org/alfresco/repo/attributes/hibernate/AttributeDAOHibernate.java index 7c2f25cc4c..ed6b235830 100644 --- a/source/java/org/alfresco/repo/attributes/hibernate/AttributeDAOHibernate.java +++ b/source/java/org/alfresco/repo/attributes/hibernate/AttributeDAOHibernate.java @@ -43,6 +43,7 @@ import org.alfresco.repo.attributes.MapEntry; import org.alfresco.repo.attributes.MapEntryDAO; import org.alfresco.repo.attributes.Attribute.Type; import org.alfresco.repo.avm.hibernate.SessionCacheChecker; +import org.alfresco.repo.domain.hibernate.DirtySessionMethodInterceptor; import org.alfresco.service.cmr.attributes.AttrQuery; import org.alfresco.service.cmr.attributes.AttrQueryHelper; import org.alfresco.util.Pair; @@ -128,6 +129,7 @@ public class AttributeDAOHibernate extends HibernateDaoSupport implements { hQuery.setParameter(param.getKey(), param.getValue()); } + DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), hQuery); List hits = (List)hQuery.list(); List> result = new ArrayList>(); for (MapEntry entry : hits) diff --git a/source/java/org/alfresco/repo/attributes/hibernate/GlobalAttributeEntryDAOHibernate.java b/source/java/org/alfresco/repo/attributes/hibernate/GlobalAttributeEntryDAOHibernate.java index 6a8c2a30fa..374ad5d603 100644 --- a/source/java/org/alfresco/repo/attributes/hibernate/GlobalAttributeEntryDAOHibernate.java +++ b/source/java/org/alfresco/repo/attributes/hibernate/GlobalAttributeEntryDAOHibernate.java @@ -32,6 +32,7 @@ import org.alfresco.repo.attributes.AttributeDAO; import org.alfresco.repo.attributes.GlobalAttributeEntry; import org.alfresco.repo.attributes.GlobalAttributeEntryDAO; import org.alfresco.repo.attributes.GlobalAttributeEntryImpl; +import org.alfresco.repo.domain.hibernate.DirtySessionMethodInterceptor; import org.hibernate.Query; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; @@ -94,6 +95,7 @@ public class GlobalAttributeEntryDAOHibernate extends HibernateDaoSupport public List getKeys() { Query query = getSession().createQuery("select gae.name from GlobalAttributeEntryImpl gae"); + DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), query); return (List)query.list(); } } diff --git a/source/java/org/alfresco/repo/attributes/hibernate/ListEntryDAOHibernate.java b/source/java/org/alfresco/repo/attributes/hibernate/ListEntryDAOHibernate.java index e35f226e5f..db4999a37a 100644 --- a/source/java/org/alfresco/repo/attributes/hibernate/ListEntryDAOHibernate.java +++ b/source/java/org/alfresco/repo/attributes/hibernate/ListEntryDAOHibernate.java @@ -32,6 +32,7 @@ import org.alfresco.repo.attributes.ListEntry; import org.alfresco.repo.attributes.ListEntryDAO; import org.alfresco.repo.attributes.ListEntryImpl; import org.alfresco.repo.attributes.ListEntryKey; +import org.alfresco.repo.domain.hibernate.DirtySessionMethodInterceptor; import org.hibernate.Query; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; @@ -76,6 +77,7 @@ public class ListEntryDAOHibernate extends HibernateDaoSupport implements { Query query = getSession().createQuery("from ListEntryImpl le where le.key.list = :list"); query.setEntity("list", list); + DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), query); return (List)query.list(); } @@ -94,6 +96,7 @@ public class ListEntryDAOHibernate extends HibernateDaoSupport implements { Query query = getSession().createQuery("select count(*) from ListEntryImpl le where le.key.list = :list"); query.setEntity("list", list); + DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), query); return ((Long)query.uniqueResult()).intValue(); } } diff --git a/source/java/org/alfresco/repo/attributes/hibernate/MapEntryDAOHibernate.java b/source/java/org/alfresco/repo/attributes/hibernate/MapEntryDAOHibernate.java index de37612950..e3931dccc4 100644 --- a/source/java/org/alfresco/repo/attributes/hibernate/MapEntryDAOHibernate.java +++ b/source/java/org/alfresco/repo/attributes/hibernate/MapEntryDAOHibernate.java @@ -32,6 +32,7 @@ import org.alfresco.repo.attributes.MapEntry; import org.alfresco.repo.attributes.MapEntryDAO; import org.alfresco.repo.attributes.MapEntryImpl; import org.alfresco.repo.attributes.MapEntryKey; +import org.alfresco.repo.domain.hibernate.DirtySessionMethodInterceptor; import org.hibernate.Query; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; @@ -76,6 +77,7 @@ public class MapEntryDAOHibernate extends HibernateDaoSupport implements { Query query = getSession().createQuery("from MapEntryImpl me where me.key.map = :map"); query.setEntity("map", mapAttr); + DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), query); return (List)query.list(); } @@ -94,6 +96,7 @@ public class MapEntryDAOHibernate extends HibernateDaoSupport implements { Query query = getSession().createQuery("select count(*) from MapEntryImpl me where me.key.map = :map"); query.setEntity("map", mapAttr); + DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), query); return ((Long)query.uniqueResult()).intValue(); } diff --git a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java index 8b5a3e186c..cd026556f0 100644 --- a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java @@ -363,7 +363,7 @@ public class AVMStoreImpl implements AVMStore, Serializable { newDir.setAncestor(child); } - dir.updateModTime(); + //dir.updateModTime(); dir.putChild(name, newDir); if (aspects != null) { @@ -433,7 +433,7 @@ public class AVMStoreImpl implements AVMStore, Serializable { newDir.setAncestor(child); } - dir.updateModTime(); + //dir.updateModTime(); dir.putChild(name, newDir); // newDir.setVersionID(getNextVersionID()); } @@ -464,7 +464,7 @@ public class AVMStoreImpl implements AVMStore, Serializable } PlainFileNodeImpl file = new PlainFileNodeImpl(this); // file.setVersionID(getNextVersionID()); - dir.updateModTime(); + //dir.updateModTime(); dir.putChild(name, file); if (child != null) { @@ -506,7 +506,7 @@ public class AVMStoreImpl implements AVMStore, Serializable } PlainFileNodeImpl file = new PlainFileNodeImpl(this); // file.setVersionID(getNextVersionID()); - dir.updateModTime(); + //dir.updateModTime(); dir.putChild(name, file); if (child != null) { @@ -578,7 +578,7 @@ public class AVMStoreImpl implements AVMStore, Serializable { newFile.setAncestor(child); } - dir.updateModTime(); + //dir.updateModTime(); dir.putChild(name, newFile); DbAccessControlList acl = dir.getAcl(); newFile.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); @@ -754,7 +754,7 @@ public class AVMStoreImpl implements AVMStore, Serializable throw new AVMNotFoundException("Does not exist: " + name); } dir.removeChild(lPath, name); - dir.updateModTime(); + //dir.updateModTime(); } /** @@ -1516,6 +1516,7 @@ public class AVMStoreImpl implements AVMStore, Serializable throw new AVMWrongTypeException("File Expected."); } ((FileNode)node).setContentData(data); + node.updateModTime(); } /** diff --git a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java index 0d1ad885cc..9633b479d5 100644 --- a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java @@ -409,6 +409,7 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec ChildEntry entry = new ChildEntryImpl(key, node); AVMDAOs.Instance().fAVMNodeDAO.flush(); AVMDAOs.Instance().fChildEntryDAO.save(entry); + AVMDAOs.Instance().fAVMNodeDAO.flush(); } /** diff --git a/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml b/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml index 9d36df097e..b5dc4d6877 100644 --- a/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml +++ b/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml @@ -363,18 +363,18 @@ DELETE FROM - avm_store_properties asp + avm_store_properties WHERE - asp.avm_store_id = :storeId AND - asp.qname_id = :qnameId + avm_store_id = :storeId AND + qname_id = :qnameId DELETE FROM - avm_store_properties asp + avm_store_properties WHERE - asp.avm_store_id = :storeId + avm_store_id = :storeId diff --git a/source/java/org/alfresco/repo/domain/PropertyValueTest.java b/source/java/org/alfresco/repo/domain/PropertyValueTest.java index 1ed400039b..07b8dbd124 100644 --- a/source/java/org/alfresco/repo/domain/PropertyValueTest.java +++ b/source/java/org/alfresco/repo/domain/PropertyValueTest.java @@ -28,8 +28,11 @@ import java.util.Locale; import junit.framework.TestCase; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.MLText; +import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; import org.springframework.context.ApplicationContext; @@ -45,15 +48,27 @@ public class PropertyValueTest extends TestCase public void testMLText() { - // single language - MLText mlText = new MLText(Locale.FRENCH, "bonjour"); - PropertyValue propertyValue = new PropertyValue(DataTypeDefinition.MLTEXT, mlText); - assertNotNull("MLText not persisted as a string", propertyValue.getStringValue()); + ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + TransactionService txnService = serviceRegistry.getTransactionService(); - // multiple languages - mlText = new MLText(Locale.GERMAN, "hallo"); - mlText.addValue(Locale.ITALIAN, "ciao"); - propertyValue = new PropertyValue(DataTypeDefinition.MLTEXT, mlText); - assertNotNull("MLText not persisted as an attribute", propertyValue.getAttributeValue()); + RetryingTransactionCallback doTestCallback = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + // single language + MLText mlText = new MLText(Locale.FRENCH, "bonjour"); + PropertyValue propertyValue = new PropertyValue(DataTypeDefinition.MLTEXT, mlText); + assertNotNull("MLText not persisted as a string", propertyValue.getStringValue()); + + // multiple languages + mlText = new MLText(Locale.GERMAN, "hallo"); + mlText.addValue(Locale.ITALIAN, "ciao"); + propertyValue = new PropertyValue(DataTypeDefinition.MLTEXT, mlText); + assertNotNull("MLText not persisted as an attribute", propertyValue.getAttributeValue()); + + return null; + } + }; + txnService.getRetryingTransactionHelper().doInTransaction(doTestCallback, false); } } diff --git a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml index f440230d19..c85e7ee918 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml @@ -170,8 +170,8 @@ - + @@ -257,16 +257,6 @@ node.uuid = :uuid - - update - org.alfresco.repo.domain.hibernate.ChildAssocImpl assoc - set - assoc.childNodeName = :newName, - assoc.childNodeNameCrc = :newNameCrc - where - assoc = :childAssoc - - select assoc, @@ -356,8 +346,8 @@ where assoc.parent.id = :parentId and assoc.typeQNameId = :typeQNameId and - assoc.childNodeName = :childNodeName and - assoc.childNodeNameCrc = :childNodeNameCrc + assoc.childNodeNameCrc = :childNodeNameCrc and + assoc.childNodeName = :childNodeName order by assoc.index, assoc.id diff --git a/source/java/org/alfresco/repo/importer/ImporterComponent.java b/source/java/org/alfresco/repo/importer/ImporterComponent.java index d75fc62a85..32a126004c 100644 --- a/source/java/org/alfresco/repo/importer/ImporterComponent.java +++ b/source/java/org/alfresco/repo/importer/ImporterComponent.java @@ -55,8 +55,6 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.XPathException; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.rule.RuleService; -import org.alfresco.service.cmr.search.ResultSet; -import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AccessStatus; @@ -1014,35 +1012,10 @@ public class ImporterComponent } else if (importedRef.startsWith("/")) { - // resolve absolute path - SearchParameters searchParameters = new SearchParameters(); - searchParameters.addStore(sourceNodeRef.getStoreRef()); - searchParameters.setLanguage(SearchService.LANGUAGE_LUCENE); - searchParameters.setQuery("PATH:\"" + importedRef + "\""); - searchParameters.excludeDataInTheCurrentTransaction((binding == null) ? true : !binding.allowReferenceWithinTransaction()); - ResultSet resultSet = null; - try + List nodeRefs = searchService.selectNodes(sourceNodeRef, importedRef, null, namespaceService, false); + if (nodeRefs.size() > 0) { - resultSet = searchService.query(searchParameters); - if (resultSet.length() > 0) - { - nodeRef = resultSet.getNodeRef(0); - } - } - catch(UnsupportedOperationException e) - { - List nodeRefs = searchService.selectNodes(sourceNodeRef, importedRef, null, namespaceService, false); - if (nodeRefs.size() > 0) - { - nodeRef = nodeRefs.get(0); - } - } - finally - { - if (resultSet != null) - { - resultSet.close(); - } + nodeRef = nodeRefs.get(0); } } else diff --git a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java index 7dcab8d3d1..e209d91023 100644 --- a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java +++ b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java @@ -2113,6 +2113,32 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest } } + /** + * Create some nodes that have the same cm:name but use associations that don't + * enforce uniqueness. + */ + public void testNonDuplicateAssocsWithSuppliedName() throws Throwable + { + Map properties = Collections.singletonMap(ContentModel.PROP_NAME, (Serializable) getName()); + NodeRef parentRef = nodeService.createNode( + rootNodeRef, + ASSOC_TYPE_QNAME_TEST_CHILDREN, + QName.createQName("parent_child"), + ContentModel.TYPE_CONTAINER).getChildRef(); + ChildAssociationRef pathARef = nodeService.createNode( + parentRef, + ASSOC_TYPE_QNAME_TEST_CHILDREN, + QName.createQName("pathA"), + ContentModel.TYPE_CONTENT, + properties); + ChildAssociationRef pathBRef = nodeService.createNode( + parentRef, + ASSOC_TYPE_QNAME_TEST_CHILDREN, + QName.createQName("pathB"), + ContentModel.TYPE_CONTENT, + properties); + } + /** * Checks that the unique constraint doesn't break delete and create within the same * transaction. diff --git a/source/java/org/alfresco/repo/node/FFCLoadsOfFiles.java b/source/java/org/alfresco/repo/node/FFCLoadsOfFiles.java new file mode 100644 index 0000000000..197a8f82c0 --- /dev/null +++ b/source/java/org/alfresco/repo/node/FFCLoadsOfFiles.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2005-2008 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.node; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.ContentWriter; +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.SearchService; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.context.ApplicationContext; + +/** + * Perform document loads and fetches of child associations in increasing numbers. + *

+ * {@link https://issues.alfresco.com/jira/browse/ETWOTWO-744} + * + * @author Derek Hulley + * @author CACEIS + * @since 2.2SP2 + */ +public class FFCLoadsOfFiles +{ + private static int totalNumDocs = 6000; + private static int docsPerTx = 2000; + private static int currentDoc = 0; + + public static void main(String[] args) + { + + // initialise app content + ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + // get registry of services + final ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + + // authenticate + AuthenticationService authenticationService = serviceRegistry.getAuthenticationService(); + authenticationService.authenticate("admin", "admin".toCharArray()); + + + // use TransactionWork to wrap service calls in a user transaction + TransactionService transactionService = serviceRegistry.getTransactionService(); + RetryingTransactionCallback exampleWork = new RetryingTransactionCallback() + { + public Object execute() throws Exception + { + doExample(serviceRegistry); + return null; + } + }; + currentDoc = 0; + while (currentDoc < totalNumDocs) + { + transactionService.getRetryingTransactionHelper().doInTransaction(exampleWork); + } + System.exit(0); + } + + + + + public static void doExample(ServiceRegistry serviceRegistry) throws Exception + { + // + // locate the company home node + // + SearchService searchService = serviceRegistry.getSearchService(); + NodeService nodeService = serviceRegistry.getNodeService(); + NamespaceService namespaceService = serviceRegistry.getNamespaceService(); + StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"); + NodeRef rootNodeRef = nodeService.getRootNode(storeRef); + List results = searchService.selectNodes(rootNodeRef, "/app:company_home", null, namespaceService, false); + if (results.size() == 0) + { + throw new AlfrescoRuntimeException("Can't find /app:company_home"); + } + NodeRef companyHomeNodeRef = results.get(0); + results = searchService.selectNodes(companyHomeNodeRef, "./cm:LoadTest", null, namespaceService, false); + final NodeRef loadTestHome; + if (results.size() == 0) + { + loadTestHome = nodeService.createNode( + companyHomeNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "LoadTest"), + ContentModel.TYPE_FOLDER).getChildRef(); + } + else + { + loadTestHome = results.get(0); + } + + if ((currentDoc + docsPerTx) > totalNumDocs) + { + docsPerTx = totalNumDocs - currentDoc; + } + // Create new Space + String spaceName = "Bulk Load Space (" + System.currentTimeMillis() + ") from " + currentDoc + " to " + (currentDoc + docsPerTx - 1) + " of " + totalNumDocs; + Map spaceProps = new HashMap(); + spaceProps.put(ContentModel.PROP_NAME, spaceName); + NodeRef newSpace = nodeService.createNode(loadTestHome, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_PREFIX, spaceName),ContentModel.TYPE_FOLDER,spaceProps).getChildRef(); + + + // create new content node within new Space home + for (int k = 1;k<=docsPerTx;k++) + { + currentDoc++; + System.out.println("About to start document " + currentDoc); + // assign name + String name = "BulkLoad (" + System.currentTimeMillis() + ") " + currentDoc ; + Map contentProps = new HashMap(); + contentProps.put(ContentModel.PROP_NAME, name); + + // create content node + // NodeService nodeService = serviceRegistry.getNodeService(); + ChildAssociationRef association = nodeService.createNode(newSpace, + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.CONTENT_MODEL_PREFIX, name), + ContentModel.TYPE_CONTENT, + contentProps); + NodeRef content = association.getChildRef(); + + // add titled aspect (for Web Client display) + Map titledProps = new HashMap(); + titledProps.put(ContentModel.PROP_TITLE, name); + titledProps.put(ContentModel.PROP_DESCRIPTION, name); + nodeService.addAspect(content, ContentModel.ASPECT_TITLED, titledProps); + + // + // write some content to new node + // + + ContentService contentService = serviceRegistry.getContentService(); + ContentWriter writer = contentService.getWriter(content, ContentModel.PROP_CONTENT, true); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.setEncoding("UTF-8"); + String text = "This is some text in a doc"; + writer.putContent(text); + System.out.println("About to get child assocs "); + //Circa +// nodeService.getChildAssocs(newSpace); + for (int count=0;count<=10000;count++) + { + nodeService.getChildAssocs(newSpace); + } + + } + //doSearch(searchService); + System.out.println("About to end transaction " ); + + } +} diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index e5ca22f87e..00930054a8 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -293,18 +293,6 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // create the node instance Pair childNodePair = nodeDaoService.newNode(parentStoreRef, newUuid, nodeTypeQName); - // We now have enough to declare the child association creation - invokeBeforeCreateChildAssociation(parentRef, childNodePair.getSecond(), assocTypeQName, assocQName, true); - - // Create the association - Pair childAssocPair = nodeDaoService.newChildAssoc( - parentNodePair.getFirst(), - childNodePair.getFirst(), - true, - assocTypeQName, - assocQName); - ChildAssociationRef childAssocRef = childAssocPair.getSecond(); - // Add defaults addDefaults(childNodePair, nodeTypeQName); @@ -316,11 +304,21 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Map propertiesAfter = nodeDaoService.getNodeProperties(childNodePair.getFirst()); + // We now have enough to declare the child association creation + invokeBeforeCreateChildAssociation(parentRef, childNodePair.getSecond(), assocTypeQName, assocQName, true); + // Ensure child uniqueness String newName = extractNameProperty(propertiesAfter); - // Ensure uniqueness. Note that the cm:name may be null, in which case the uniqueness is still - setChildNameUnique(childAssocPair, newName, null); // ensure uniqueness - + // Create the association + Pair childAssocPair = nodeDaoService.newChildAssoc( + parentNodePair.getFirst(), + childNodePair.getFirst(), + true, + assocTypeQName, + assocQName, + newName); + ChildAssociationRef childAssocRef = childAssocPair.getSecond(); + // Invoke policy behaviour invokeOnCreateNode(childAssocRef); invokeOnCreateChildAssociation(childAssocRef, true); @@ -485,8 +483,18 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl " index: " + index, childAssocRef); } + // Get the child node name + Map childNodeProperties = nodeDaoService.getNodeProperties(childNodeId); + String childNodeName = extractNameProperty(childNodeProperties); // set the index - nodeDaoService.updateChildAssoc(assocPair.getFirst(), parentNodeId, childNodeId, assocTypeQName, assocQName, index); + nodeDaoService.updateChildAssoc( + assocPair.getFirst(), + parentNodeId, + childNodeId, + assocTypeQName, + assocQName, + index, + childNodeName); } public QName getType(NodeRef nodeRef) throws InvalidNodeRefException @@ -800,8 +808,18 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Invoke policy behaviours invokeBeforeCreateChildAssociation(parentRef, childRef, assocTypeQName, assocQName, false); + // Get the node's name, if present + Map childNodeProperties = nodeDaoService.getNodeProperties(childNodePair.getFirst()); + String childNodeName = extractNameProperty(childNodeProperties); + // make the association - Pair childAssocPair = nodeDaoService.newChildAssoc(parentNodeId, childNodeId, false, assocTypeQName, assocQName); + Pair childAssocPair = nodeDaoService.newChildAssoc( + parentNodeId, + childNodeId, + false, + assocTypeQName, + assocQName, + childNodeName); ChildAssociationRef childAssocRef = childAssocPair.getSecond(); // ensure name uniqueness setChildNameUnique(childAssocPair, childNodePair); @@ -1889,6 +1907,9 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } } + // Get the new node's cm:name + Map newNodeProperties = nodeDaoService.getNodeProperties(nodeToMoveId); + String newNodeChildName = extractNameProperty(newNodeProperties); // Modify the association directly. We do this AFTER the change of the node's store so that // the association reference returned is correct. Pair newParentAssocPair = nodeDaoService.updateChildAssoc( @@ -1897,7 +1918,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl nodeToMoveId, assocTypeQName, assocQName, - -1); + -1, + newNodeChildName); ChildAssociationRef newParentAssocRef = newParentAssocPair.getSecond(); // Handle indexing differently if it is a store move @@ -2149,6 +2171,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl List allResults = new ArrayList(100); allResults.addAll(moveChildrenResults); allResults.addAll(indexChildrenResults); + // Done return allResults; } @@ -2298,4 +2321,15 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } return results; } + + /** + * Cleans up transactions and deleted nodes that are older than the given minimum age. + * + * @param minAge the minimum age of a transaction or deleted node + * @return Returns log message results + */ + private List cleanUpTransactions(long minAge) + { + return null; + } } diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java index 8ac31b8d9e..a15c6ea3e0 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java @@ -386,6 +386,21 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest assertEquals("Setting of MLText over String failed.", mlText, mlTextCheck); } + /** + * Ensure that plain strings going into MLText properties is handled + */ + @SuppressWarnings("unchecked") + public void testSingleStringMLTextProperty() throws Exception + { + // Set the property with single-value MLText + MLText mlText = new MLText(); + mlText.addValue(Locale.GERMAN, "Sehr gut!"); + nodeService.setProperty(rootNodeRef, PROP_QNAME_ML_TEXT_VALUE, mlText); + // Get it back and check + MLText mlTextCheck = (MLText) nodeService.getProperty(rootNodeRef, PROP_QNAME_ML_TEXT_VALUE); + assertEquals("Setting of MLText over String failed.", mlText, mlTextCheck); + } + public void testDuplicatePrimaryParentHandling() throws Exception { Map assocRefs = buildNodeGraph(); @@ -403,7 +418,8 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest n8Pair.getFirst(), true, ContentModel.ASSOC_CONTAINS, - QName.createQName(NAMESPACE, "n1pn8")); + QName.createQName(NAMESPACE, "n1pn8"), + null); // Now get the node primary parent nodeService.getPrimaryParent(n8Ref); diff --git a/source/java/org/alfresco/repo/node/db/NodeDaoService.java b/source/java/org/alfresco/repo/node/db/NodeDaoService.java index 7fe5b41339..d977e33534 100644 --- a/source/java/org/alfresco/repo/node/db/NodeDaoService.java +++ b/source/java/org/alfresco/repo/node/db/NodeDaoService.java @@ -170,7 +170,8 @@ public interface NodeDaoService public void deleteNode(Long nodeId); /** - * @return Returns the persisted and filled association's ID + * @param name the cm:name to apply to the association + * @return Returns the persisted and filled association's ID * * @see ChildAssoc */ @@ -180,7 +181,8 @@ public interface NodeDaoService Long childNodeId, boolean isPrimary, QName assocTypeQName, - QName qname); + QName qname, + String name); /** * Change the name of the child node. @@ -201,7 +203,8 @@ public interface NodeDaoService Long childNodeId, QName assocTypeQName, QName qname, - int index); + int index, + String childName); /** * Interface used to iterate over results from child association queries 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 162feb9e96..7334ba953a 100644 --- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java @@ -79,6 +79,8 @@ import org.alfresco.repo.security.permissions.impl.AclDaoComponent; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.TransactionAwareSingleton; import org.alfresco.repo.transaction.TransactionalDao; +import org.alfresco.service.cmr.dictionary.AssociationDefinition; +import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryException; import org.alfresco.service.cmr.dictionary.DictionaryService; @@ -1347,6 +1349,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements * @param cascade true to cascade delete * @param deletedChildAssocIds previously deleted child associations */ + @SuppressWarnings("unchecked") private void deleteNodeInternal(Node node, boolean cascade, Set deletedChildAssocIds) { final Long nodeId = node.getId(); @@ -1530,25 +1533,44 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements Long childNodeId, boolean isPrimary, QName assocTypeQName, - QName assocQName) + QName assocQName, + String newName) { Node parentNode = (Node) getSession().get(NodeImpl.class, parentNodeId); Node childNode = (Node) getSession().get(NodeImpl.class, childNodeId); - // assign a random name to the node - String name = GUID.generate(); + final Pair childNameUnique = getChildNameUnique(assocTypeQName, newName); ChildAssoc assoc = new ChildAssocImpl(); assoc.setTypeQName(qnameDAO, assocTypeQName); - assoc.setChildNodeName(name); - assoc.setChildNodeNameCrc(-1L); // random names compete only with each other + assoc.setChildNodeName(childNameUnique.getFirst()); + assoc.setChildNodeNameCrc(childNameUnique.getSecond()); assoc.setQName(qnameDAO, assocQName); assoc.setIsPrimary(isPrimary); assoc.setIndex(-1); // maintain inverse sets assoc.buildAssociation(parentNode, childNode); // persist it - Long assocId = (Long) getHibernateTemplate().save(assoc); + Long assocId; + try + { + assocId = (Long) getHibernateTemplate().save(assoc); + } + catch (Throwable e) + { + // There is already an entity + if (isDebugEnabled) + { + logger.debug( + "Duplicate child association detected: \n" + + " Parent Node: " + parentNode.getId() + "\n" + + " Child Name Used: " + childNameUnique); + } + throw new DuplicateChildNodeNameException( + parentNode.getNodeRef(), + assocTypeQName, + childNameUnique.getFirst()); + } // Add it to the cache Set oldParentAssocIds = parentAssocsCache.get(childNode.getId()); if (oldParentAssocIds != null) @@ -1599,50 +1621,15 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements final ChildAssoc childAssoc = getChildAssocNotNull(childAssocId); final Node parentNode = childAssoc.getParent(); - String childNameNew = null; - long crc = -1; - if (childName == null) - { - // If the name assigned is null, then the name that will be assigned will - // be random. Ofcourse, if the association already has a random name assigned - // to it then there is no reason to assign a new one. The update of the child - // association is only required if the existing CRC value is not -1. - long existingCrc = childAssoc.getChildNodeNameCrc(); - if (existingCrc == -1L) - { - if (isDebugEnabled) - { - logger.debug( - "Child association name assignment is already random-based (non-clashing): \n" + - " Parent Node: " + parentNode.getId() + "\n" + - " Child Assoc: " + childAssoc.getId()); - } - // Shortcut here - return; - } - - // random names compete only with each other, i.e. not at all - childNameNew = GUID.generate(); - // The CRC of -1 indicates that the cm:name equivalent is non-clashing, i.e. a GUID - crc = -1L; - } - else - { - // assigned names compete exactly - childNameNew = childName.toLowerCase(); - crc = getCrc(childNameNew); - } - - final String childNameNewShort = getShortName(childNameNew); - final long childNameNewCrc = crc; + QName childAssocTypeQName = childAssoc.getTypeQName(qnameDAO); + final Pair childNameUnique = getChildNameUnique(childAssocTypeQName, childName); HibernateCallback callback = new HibernateCallback() { public Object doInHibernate(Session session) { - // Update the association - childAssoc.setChildNodeName(childNameNewShort); - childAssoc.setChildNodeNameCrc(childNameNewCrc); + childAssoc.setChildNodeName(childNameUnique.getFirst()); + childAssoc.setChildNodeNameCrc(childNameUnique.getSecond().longValue()); // Flush again to force a DB constraint here DirtySessionMethodInterceptor.flushSession(session, true); // Done @@ -1663,13 +1650,13 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements { logger.debug( "Duplicate child association detected: \n" + - " Parent Node: " + parentNode.getId() + "\n" + - " Child Name: " + childName); + " Parent Node: " + parentNode.getId() + "\n" + + " Child Name Used: " + childNameUnique); } throw new DuplicateChildNodeNameException( parentNode.getNodeRef(), childAssoc.getTypeQName(qnameDAO), - childName); + childNameUnique.getFirst()); } // Done @@ -1681,6 +1668,49 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements " Child Assoc: " + childAssoc); } } + + /** + * Apply the cm:name to the child association. If the child name is null then + * a GUID is generated as a substitute. + * + * @param childName the cm:name applying to the association. + */ + private Pair getChildNameUnique(QName assocTypeQName, String childName) + { + String childNameNewShort; // + long childNameNewCrc = -1L; // By default, they don't compete + + if (childName == null) + { + childNameNewShort = GUID.generate(); + childNameNewCrc = -1L * getCrc(childNameNewShort); + } + else + { + AssociationDefinition assocDef = dictionaryService.getAssociation(assocTypeQName); + if (!assocDef.isChild()) + { + childNameNewShort = GUID.generate(); + childNameNewCrc = -1L * getCrc(childNameNewShort); + } + else + { + ChildAssociationDefinition childAssocDef = (ChildAssociationDefinition) assocDef; + if (childAssocDef.getDuplicateChildNamesAllowed()) + { + childNameNewShort = GUID.generate(); + childNameNewCrc = -1L * getCrc(childNameNewShort); + } + else + { + String childNameNewLower = childName.toLowerCase(); + childNameNewShort = getShortName(childNameNewLower); + childNameNewCrc = getCrc(childNameNewLower); + } + } + } + return new Pair(childNameNewShort, childNameNewCrc); + } public Pair updateChildAssoc( Long childAssocId, @@ -1688,7 +1718,8 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements Long childNodeId, QName assocTypeQName, QName assocQName, - int index) + int index, + String childName) { final ChildAssoc childAssoc = getChildAssocNotNull(childAssocId); final boolean isPrimary = childAssoc.getIsPrimary(); @@ -1700,9 +1731,9 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements final NodeRef newChildNodeRef = newChildNode.getNodeRef(); // Reset the cm:name duplicate handling. This has to be redone, if required. - String name = GUID.generate(); - childAssoc.setChildNodeName(name); - childAssoc.setChildNodeNameCrc(-1L); + Pair childNameUnique = getChildNameUnique(assocTypeQName, childName); + childAssoc.setChildNodeName(childNameUnique.getFirst()); + childAssoc.setChildNodeNameCrc(childNameUnique.getSecond()); childAssoc.buildAssociation(newParentNode, newChildNode); childAssoc.setTypeQName(qnameDAO, assocTypeQName); @@ -2170,8 +2201,8 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_BY_TYPE_AND_NAME) .setLong("parentId", parentNodeId) .setLong("typeQNameId", assocTypeQNamePair.getFirst()) - .setString("childNodeName", childNameShort) - .setLong("childNodeNameCrc", childNameLowerCrc); + .setLong("childNodeNameCrc", childNameLowerCrc) + .setString("childNodeName", childNameShort); DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.uniqueResult(); } @@ -2904,9 +2935,15 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements final StoreRef storeRef, final ObjectArrayQueryCallback resultsCallback) { - final Long personTypeQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.TYPE_PERSON).getFirst(); - final Long usernamePropQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.PROP_USERNAME).getFirst(); - final Long sizeCurrentPropQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.PROP_SIZE_CURRENT).getFirst(); + final Pair usernamePropQNamePair = qnameDAO.getQName(ContentModel.PROP_USERNAME); + final Pair sizeCurrentPropQNamePair = qnameDAO.getQName(ContentModel.PROP_SIZE_CURRENT); + final Pair personTypeQNamePair = qnameDAO.getQName(ContentModel.TYPE_PERSON); + + // Shortcut the query if the QNames don't exist + if (usernamePropQNamePair == null || sizeCurrentPropQNamePair == null || personTypeQNamePair == null) + { + return; + } HibernateCallback callback = new HibernateCallback() { @@ -2916,9 +2953,9 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_USERS_WITHOUT_USAGE) .setString("storeProtocol", storeRef.getProtocol()) .setString("storeIdentifier", storeRef.getIdentifier()) - .setParameter("usernamePropQNameID", usernamePropQNameEntityId) // cm:username - .setParameter("sizeCurrentPropQNameID", sizeCurrentPropQNameEntityId) // cm:sizeCurrent - .setParameter("personTypeQNameID", personTypeQNameEntityId) // cm:person + .setParameter("usernamePropQNameID", usernamePropQNamePair.getFirst()) // cm:username + .setParameter("sizeCurrentPropQNameID", sizeCurrentPropQNamePair.getFirst()) // cm:sizeCurrent + .setParameter("personTypeQNameID", personTypeQNamePair.getFirst()) // cm:person ; DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.scroll(ScrollMode.FORWARD_ONLY); diff --git a/source/java/org/alfresco/repo/node/index/AVMFullIndexRecoveryComponent.java b/source/java/org/alfresco/repo/node/index/AVMFullIndexRecoveryComponent.java index 3b7c38afe6..4037765951 100644 --- a/source/java/org/alfresco/repo/node/index/AVMFullIndexRecoveryComponent.java +++ b/source/java/org/alfresco/repo/node/index/AVMFullIndexRecoveryComponent.java @@ -266,10 +266,8 @@ public class AVMFullIndexRecoveryComponent extends AbstractReindexComponent } - private void recoverStore(String store, RecoveryMode mode) + private void recoverStore(final String store, final RecoveryMode mode) { - int tracker = -1; - if (mode == RecoveryMode.AUTO) { logger.info(" Auto recovering index for " + store); @@ -284,80 +282,43 @@ public class AVMFullIndexRecoveryComponent extends AbstractReindexComponent avmSnapShotTriggeredIndexingMethodInterceptor.createIndex(store); } - int latest = avmService.getLatestSnapshotID(store); - if (latest <= 0) - { - return; - } - - boolean wasRecovered = false; - if (avmSnapShotTriggeredIndexingMethodInterceptor.getIndexMode(store) != IndexMode.UNINDEXED) { - for (int i = 0; i <= latest; i++) + final int latest = avmService.getLatestSnapshotID(store); + if (latest <= 0) { - if (isShuttingDown()) - { - return; - } - wasRecovered = recoverSnapShot(store, i, mode, wasRecovered); - if (i * 10l / latest > tracker) - { - tracker = (int) (i * 10l / latest); - if (logger.isDebugEnabled()) - { - logger.debug(" Store " + store + " " + (tracker * 10) + "% complete"); - } - } + return; } + + final int latestIndexed = avmSnapShotTriggeredIndexingMethodInterceptor.getLastIndexedSnapshot(store); + + RetryingTransactionCallback reindexWork = new RetryingTransactionCallback() + { + public Object execute() throws Exception + { + + if (mode == RecoveryMode.AUTO) + { + logger.info(" Rebuilding index for snapshots " + latestIndexed +" to "+latest); + avmSnapShotTriggeredIndexingMethodInterceptor.indexSnapshot(store, latestIndexed, latest); + + } + else + { + logger.info(" Rebuilding index for snapshots " + 0 +" to "+latest); + avmSnapShotTriggeredIndexingMethodInterceptor.indexSnapshot(store, 0, latest); + } + return null; + + } + }; + transactionService.getRetryingTransactionHelper().doInTransaction(reindexWork, true, true); + } + if (logger.isDebugEnabled()) { logger.debug(" Index updated for " + store); } } - - private boolean recoverSnapShot(final String store, final int id, final RecoveryMode mode, final boolean wasRecovered) - { - if (logger.isDebugEnabled()) - { - logger.debug(" Reindexing avm store: " + store + " snapshot id " + id); - } - - RetryingTransactionCallback reindexWork = new RetryingTransactionCallback() - { - public Boolean execute() throws Exception - { - if (wasRecovered) - { - avmSnapShotTriggeredIndexingMethodInterceptor.indexSnapshot(store, id - 1, id); - return true; - } - else - { - if (mode == RecoveryMode.AUTO) - { - if (!avmSnapShotTriggeredIndexingMethodInterceptor.isSnapshotIndexed(store, id)) - { - avmSnapShotTriggeredIndexingMethodInterceptor.indexSnapshot(store, id - 1, id); - return true; - } - else - { - return wasRecovered; - } - } - else - { - avmSnapShotTriggeredIndexingMethodInterceptor.indexSnapshot(store, id - 1, id); - return true; - } - } - - } - }; - return transactionService.getRetryingTransactionHelper().doInTransaction(reindexWork, true, true); - // done - } - } diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java index bc48a802c0..91c206bbae 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java @@ -265,9 +265,9 @@ public class AuthenticationTest extends TestCase // new TX - userTransaction.commit(); - userTransaction = transactionService.getUserTransaction(); - userTransaction.begin(); + //userTransaction.commit(); + //userTransaction = transactionService.getUserTransaction(); + //userTransaction.begin(); pubAuthenticationService.validate(ticket); userName = pubAuthenticationService.getCurrentUserName(); @@ -319,6 +319,20 @@ public class AuthenticationTest extends TestCase } } + public void testNewTicketOnLogin() + { + authenticationComponent.setSystemUserAsCurrentUser(); + pubAuthenticationService.createAuthentication("Andy", "auth1".toCharArray()); + authenticationComponent.clearCurrentSecurityContext(); + + // authenticate with this user details + pubAuthenticationService.authenticate("Andy", "auth1".toCharArray()); + String ticket1 = pubAuthenticationService.getCurrentTicket(); + pubAuthenticationService.authenticate("Andy", "auth1".toCharArray()); + assertFalse(ticket1.equals(pubAuthenticationService.getCurrentTicket())); + + } + public void testGuest() { authenticationService.authenticate("GUEST", "".toCharArray()); diff --git a/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java b/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java index fda4d945ce..71465d636b 100644 --- a/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java +++ b/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java @@ -749,6 +749,7 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo // Map the passthru username to an Alfresco person + clearCurrentSecurityContext(); setCurrentUser( username); // Debug @@ -912,6 +913,7 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo // Map the passthru username to an Alfresco person + clearCurrentSecurityContext(); setCurrentUser( username); } diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java b/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java index 09c79a8640..0e91c628ae 100644 --- a/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java +++ b/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java @@ -36,8 +36,11 @@ import junit.framework.TestCase; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.MutableAuthenticationDao; +import org.alfresco.repo.security.permissions.impl.AclDaoComponent; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; @@ -68,6 +71,10 @@ public class AuthorityServiceTest extends TestCase private UserTransaction tx; + private AclDaoComponent aclDaoComponent; + + private NodeService nodeService; + public AuthorityServiceTest() { super(); @@ -83,6 +90,8 @@ public class AuthorityServiceTest extends TestCase pubAuthorityService = (AuthorityService) ctx.getBean("AuthorityService"); personService = (PersonService) ctx.getBean("personService"); authenticationDAO = (MutableAuthenticationDao) ctx.getBean("authenticationDao"); + aclDaoComponent = (AclDaoComponent) ctx.getBean("aclDaoComponent"); + nodeService = (NodeService) ctx.getBean("nodeService"); authenticationComponentImpl.setSystemUserAsCurrentUser(); @@ -103,6 +112,13 @@ public class AuthorityServiceTest extends TestCase { if (personService.personExists(user)) { + NodeRef person = personService.getPerson(user); + NodeRef hf = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER)); + if(hf != null) + { + nodeService.deleteNode(hf); + } + aclDaoComponent.deleteAccessControlEntries(user); personService.deletePerson(user); } if (authenticationDAO.userExists(user))