diff --git a/config/alfresco/audit/alfresco-audit-access.xml b/config/alfresco/audit/alfresco-audit-access.xml index 4da6bf464c..61e8457703 100644 --- a/config/alfresco/audit/alfresco-audit-access.xml +++ b/config/alfresco/audit/alfresco-audit-access.xml @@ -28,9 +28,9 @@ - - - + + + diff --git a/config/alfresco/bootstrap/imapSpacesTemplates.acp b/config/alfresco/bootstrap/imapSpacesTemplates.acp deleted file mode 100644 index 680891c37e..0000000000 Binary files a/config/alfresco/bootstrap/imapSpacesTemplates.acp and /dev/null differ diff --git a/config/alfresco/bootstrap/imapSpacesTemplates.xml b/config/alfresco/bootstrap/imapSpacesTemplates.xml new file mode 100644 index 0000000000..95c5e54881 --- /dev/null +++ b/config/alfresco/bootstrap/imapSpacesTemplates.xml @@ -0,0 +1,427 @@ + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for share - ${version.default} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_share.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=en_US_ + emailbody_textplain_share.ftl + + emailbody_textplain_share.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for explorer - ${version.default} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=en_US_ + emailbody_textplain_alfresco.ftl + + emailbody_textplain_alfresco.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for explorer - ${version.default} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=en_US_ + emailbody_texthtml_alfresco.ftl + + emailbody_texthtml_alfresco.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for share - ${version.default} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=en_US_ + emailbody_texthtml_share.ftl + + emailbody_texthtml_share.ftl + + + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for share - ${version.german} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_de.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=de + emailbody_textplain_share_de.ftl + + emailbody_textplain_share_de.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for explorer - ${version.german} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_de.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=de + emailbody_textplain_alfresco_de.ftl + + emailbody_textplain_alfresco_de.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for explorer - ${version.german} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_de.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=de + emailbody_texthtml_alfresco_de.ftl + + emailbody_texthtml_alfresco_de.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for share - ${version.german} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_de.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=de + emailbody_texthtml_share_de.ftl + + emailbody_texthtml_share_de.ftl + + + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for share - ${version.spanish} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_es.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=es + emailbody_textplain_share_es.ftl + + emailbody_textplain_share_es.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for explorer - ${version.spanish} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_es.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=es + emailbody_textplain_alfresco_es.ftl + + emailbody_textplain_alfresco_es.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for explorer - ${version.spanish} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_es.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=es + emailbody_texthtml_alfresco_es.ftl + + emailbody_texthtml_alfresco_es.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for share - ${version.spanish} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_es.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=es + emailbody_texthtml_share_es.ftl + + emailbody_texthtml_share_es.ftl + + + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for share - ${version.french} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_fr.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=fr + emailbody_textplain_share_fr.ftl + + emailbody_textplain_share_fr.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for explorer - ${version.french} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_fr.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=fr + emailbody_textplain_alfresco_fr.ftl + + emailbody_textplain_alfresco_fr.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for explorer - ${version.french} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_fr.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=fr + emailbody_texthtml_alfresco_fr.ftl + + emailbody_texthtml_alfresco_fr.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for share - ${version.french} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_fr.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=fr + emailbody_texthtml_share_fr.ftl + + emailbody_texthtml_share_fr.ftl + + + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for share - ${version.italian} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_it.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=it + emailbody_textplain_share_it.ftl + + emailbody_textplain_share_it.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for explorer - ${version.italian} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_it.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=it + emailbody_textplain_alfresco_it.ftl + + emailbody_textplain_alfresco_it.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for explorer - ${version.italian} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_it.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=it + emailbody_texthtml_alfresco_it.ftl + + emailbody_texthtml_alfresco_it.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for share - ${version.italian} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_it.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=it + emailbody_texthtml_share_it.ftl + + emailbody_texthtml_share_it.ftl + + + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for share - ${version.japanese} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_ja.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=ja + emailbody_textplain_share_ja.ftl + + emailbody_textplain_share_ja.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_textplain.description} for explorer - ${version.japanese} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_ja.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=ja + emailbody_textplain_alfresco_ja.ftl + + emailbody_textplain_alfresco_ja.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for explorer - ${version.japanese} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_ja.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=ja + emailbody_texthtml_alfresco_ja.ftl + + emailbody_texthtml_alfresco_ja.ftl + + + + + + + + + + + + true + ${spaces.imap_templates.emailbody_texthtml.description} for share - ${version.japanese} + contentUrl=classpath:alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_ja.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=ja + emailbody_texthtml_share_ja.ftl + + emailbody_texthtml_share_ja.ftl + + + + + + \ No newline at end of file diff --git a/config/alfresco/bootstrap/spaces.xml b/config/alfresco/bootstrap/spaces.xml index 32f9c10fac..67aec4fba4 100644 --- a/config/alfresco/bootstrap/spaces.xml +++ b/config/alfresco/bootstrap/spaces.xml @@ -134,6 +134,13 @@ ${spaces.user_homes.name} ${spaces.user_homes.description} + + + ${spaces.imap_attachments.name} + space-icon-default + ${spaces.imap_attachments.name} + ${spaces.imap_attachments.description} + diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco.ftl new file mode 100644 index 0000000000..babd395012 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco.ftl @@ -0,0 +1,80 @@ + + + + + + + + + + +
+

Document (name): ${document.name}

+
+

Metadata

+ + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
Title:${document.properties.title}
Title: 
Description:${document.properties.description}
Description: 
Creator:${document.properties.creator}
Created:${document.properties.created?datetime}
Modifier:${document.properties.modifier}
Modified:${document.properties.modified?datetime}
Size:${document.size / 1024} Kb
+
+

Content links

+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_de.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_de.ftl new file mode 100644 index 0000000000..e3a8cd9198 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_de.ftl @@ -0,0 +1,80 @@ + + + + + + + + + + +
+

Dokument (Name): ${document.name}

+
+

Metadaten

+ + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
Titel:${document.properties.title}
Titel: 
Beschreibung:${document.properties.description}
Beschreibung: 
Ersteller:${document.properties.creator}
Erstellt am:${document.properties.created?datetime}
Bearbeiter:${document.properties.modifier}
Bearbeitet am:${document.properties.modified?datetime}
Größe:${document.size / 1024} Kb
+
+

Links zum Inhalt

+ + + + + + + + + + + + + + + + diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_es.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_es.ftl new file mode 100644 index 0000000000..da53f8ac35 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_es.ftl @@ -0,0 +1,87 @@ + + + + + + + + + + +
+

Documento (nombre): ${document.name}

+
+

Metadatos

+ + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
Título:${document.properties.title}
Título: 
Descripción:${document.properties.description}
Descripción: 
Creador:${document.properties.creator}
Creado:${document.properties.created?datetime}
Modificador:${document.properties.modifier}
Modificado:${document.properties.modified?datetime}
Tamaño:${document.size / 1024} KB
+
+

Enlaces de contenido:

+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_fr.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_fr.ftl new file mode 100644 index 0000000000..1cc6f3066c --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_fr.ftl @@ -0,0 +1,82 @@ + + + + + + + + + + +
+

Document (nom) : ${document.name}

+
+

Métadonnées

+ + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
Titre :${document.properties.title}
Titre : 
Description :${document.properties.description}
Description : 
Créateur :${document.properties.creator}
Créé :${document.properties.created?datetime}
Modificateur :${document.properties.modifier}
Modifié :${document.properties.modified?datetime}
Taille :${document.size / 1024} Ko
+
+

Liens de contenu

+ + + + + + + + + + + + + + + + + + diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_it.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_it.ftl new file mode 100644 index 0000000000..7cfa6510b3 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_it.ftl @@ -0,0 +1,81 @@ + + + + + + + + + + +
+

Documento (nome): ${document.name}

+
+

Metadati

+ + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
Titolo:${document.properties.title}
Titolo: 
Descrizione:${document.properties.description}
Descrizione: 
Autore:${document.properties.creator}
Data di creazione:${document.properties.created?datetime}
Modificatore:${document.properties.modifier}
Data di modifica:${document.properties.modified?datetime}
Dimensioni:${document.size / 1024} Kb
+
+

Collegamenti del contenuto

+ + + + + + + + + + + + + + + + + diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_ja.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_ja.ftl new file mode 100644 index 0000000000..5d7234d18f --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_alfresco_ja.ftl @@ -0,0 +1,80 @@ + + + + + + + + + + +
+

文書 (名前): ${document.name}

+
+

メタデータ

+ + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
タイトル:${document.properties.title}
タイトル: 
説明:${document.properties.description}
説明: 
作成者:${document.properties.creator}
作成日時:${document.properties.created?datetime}
修正者:${document.properties.modifier}
修正日時:${document.properties.modified?datetime}
サイズ: ${document.size / 1024} KB
+
+

コンテンツリンク

+ + + + + + + + + + + + + + + + diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share.ftl new file mode 100644 index 0000000000..824b4c6f5d --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share.ftl @@ -0,0 +1,98 @@ + + + + + + + + + + +
+

Document (name): ${document.name}

+
+
+ Metadata + + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
Title:${document.properties.title}
Title: 
Description:${document.properties.description}
Description: 
Creator:${document.properties.creator}
Created:${document.properties.created?datetime}
Modifier:${document.properties.modifier}
Modified:${document.properties.modified?datetime}
Size:${document.size / 1024} Kb
+
+
+ Content links + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_de.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_de.ftl new file mode 100644 index 0000000000..696f5008be --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_de.ftl @@ -0,0 +1,98 @@ + + + + + + + + + + +
+

Dokument (Name): ${document.name}

+
+
+ Metadata + + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
Titel:${document.properties.title}
Titel: 
Beschreibung:${document.properties.description}
Beschreibung: 
Ersteller:${document.properties.creator}
Erstellt am:${document.properties.created?datetime}
Bearbeiter:${document.properties.modifier}
Bearbeitet am:${document.properties.modified?datetime}
Größe:${document.size / 1024} Kb
+
+
+ Links zum Inhalt + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_es.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_es.ftl new file mode 100644 index 0000000000..de2119d36b --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_es.ftl @@ -0,0 +1,98 @@ + + + + + + + + + + +
+

Documento (nombre): ${document.name}

+
+
+ Metadatos + + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
Título:${document.properties.title}
Título: 
Descripción:${document.properties.description}
Descripción: 
Creador:${document.properties.creator}
Creado:${document.properties.created?datetime}
Modificador:${document.properties.modifier}
Modificado:${document.properties.modified?datetime}
Tamaño:${document.size / 1024} Kb
+
+
+ Enlaces de contenido: + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_fr.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_fr.ftl new file mode 100644 index 0000000000..5ad655c61f --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_fr.ftl @@ -0,0 +1,98 @@ + + + + + + + + + + +
+

Document (nom) : ${document.name}

+
+
+ Métadonnées + + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
Titre :${document.properties.title}
Titre : 
Description :${document.properties.description}
Description : 
Créateur :${document.properties.creator}
Créé :${document.properties.created?datetime}
Modificateur :${document.properties.modifier}
Modifié :${document.properties.modified?datetime}
Taille :${document.size / 1024} Kb
+
+
+ Liens de contenu + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_it.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_it.ftl new file mode 100644 index 0000000000..9eb1ebd16d --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_it.ftl @@ -0,0 +1,98 @@ + + + + + + + + + + +
+

Documento (nome): ${document.name}

+
+
+ Metadati + + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
Titolo:${document.properties.title}
Titolo: 
Descrizione:${document.properties.description}
Descrizione: 
Autore:${document.properties.creator}
Data di creazione:${document.properties.created?datetime}
Modificatore:${document.properties.modifier}
Data di modifica:${document.properties.modified?datetime}
Dimensioni:${document.size / 1024} Kb
+
+
+ Collegamenti del contenuto + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_ja.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_ja.ftl new file mode 100644 index 0000000000..df927dfe7f --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_texthtml_share_ja.ftl @@ -0,0 +1,98 @@ + + + + + + + + + + +
+

文書 (名前): ${document.name}

+
+
+メタデータ + + <#if document.properties.title?exists> + + <#else> + + + <#if document.properties.description?exists> + + <#else> + + + + + + + +
タイトル:${document.properties.title}
タイトル: 
説明:${document.properties.description}
説明: 
作成者:${document.properties.creator}
作成日時:${document.properties.created?datetime}
修正者:${document.properties.modifier}
修正日時:${document.properties.modified?datetime}
サイズ:${document.size / 1024} Kb
+
+
+ コンテンツリンク + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco.ftl new file mode 100644 index 0000000000..155102daa6 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco.ftl @@ -0,0 +1,27 @@ +------------------------------------------------------------------------------ +Document name: ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +Title: ${document.properties.title} + <#else> +Title: NONE + + <#if document.properties.description?exists> +Description: ${document.properties.description} + <#else> +Description: NONE + +Creator: ${document.properties.creator} +Created: ${document.properties.created?datetime} +Modifier: ${document.properties.modifier} +Modified: ${document.properties.modified?datetime} +Size: ${document.size / 1024} Kb + + +CONTENT LINKS + +Content folder: ${contextUrl}/navigate/browse${document.parent.webdavUrl} +Content URL: ${contextUrl}${document.url} +Download URL: ${contextUrl}${document.downloadUrl} +WebDAV URL: ${contextUrl}${document.webdavUrl} diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_de.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_de.ftl new file mode 100644 index 0000000000..03487e9290 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_de.ftl @@ -0,0 +1,25 @@ +------------------------------------------------------------------------------ +Dokumentname: ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +Titel: ${document.properties.title} + <#else> +Titel: KEINER + + <#if document.properties.description?exists> +Beschreibung: ${document.properties.description} + <#else> +Beschreibung: KEINE + +Ersteller: ${document.properties.creator} +Erstellt am: ${document.properties.created?datetime} +Bearbeiter: ${document.properties.modifier} +Bearbeitet am: ${document.properties.modified?datetime} +Größe: ${document.size / 1024} Kb + + +LINKS ZUM INHALT + +URL zum Inhalt: ${document.shareUrl} + diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_es.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_es.ftl new file mode 100644 index 0000000000..c69761574d --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_es.ftl @@ -0,0 +1,25 @@ +------------------------------------------------------------------------------ +Nombre del documento: ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +Título: ${document.properties.title} + <#else> +Título: NINGUNO + + <#if document.properties.description?exists> +Descripción: ${document.properties.description} + <#else> +Descripción: NINGUNA + +Creador: ${document.properties.creator} +Creado: ${document.properties.created?datetime} +Modificador: ${document.properties.modifier} +Modificado: ${document.properties.modified?datetime} +Tamaño: ${document.size / 1024} KB + + +ENLACES DE CONTENIDO + +Dirección URL de contenido: ${document.shareUrl} + diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_fr.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_fr.ftl new file mode 100644 index 0000000000..8b6fbcc252 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_fr.ftl @@ -0,0 +1,25 @@ +------------------------------------------------------------------------------ +Nom du document : ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +Titre : ${document.properties.title} + <#else> +Titre : AUCUN + + <#if document.properties.description?exists> +Description : ${document.properties.description} + <#else> +Description : AUCUN + +Créateur : ${document.properties.creator} +Créé : ${document.properties.created?datetime} +Modificateur : ${document.properties.modifier} +Modifié : ${document.properties.modified?datetime} +Taille : ${document.size / 1024} Ko + + +LIENS DE CONTENU + +URL de contenu : ${document.shareUrl} + diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_it.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_it.ftl new file mode 100644 index 0000000000..8fa97e2386 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_it.ftl @@ -0,0 +1,25 @@ +------------------------------------------------------------------------------ +Nome documento: ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +Titolo: ${document.properties.title} + <#else> +Titolo: NESSUNO + + <#if document.properties.description?exists> +Descrizione: ${document.properties.description} + <#else> +Descrizione: NESSUNA + +Autore: ${document.properties.creator} +Data di creazione: ${document.properties.created?datetime} +Modificatore: ${document.properties.modifier} +Data di modifica: ${document.properties.modified?datetime} +Dimensioni: ${document.size / 1024} Kb + + +COLLEGAMENTI DEL CONTENUTO + +URL del contenuto: ${document.shareUrl} + diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_ja.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_ja.ftl new file mode 100644 index 0000000000..f2670c8811 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_alfresco_ja.ftl @@ -0,0 +1,29 @@ +------------------------------------------------------------------------------ +ドキュメント名: ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +タイトル: ${document.properties.title} + <#else> +タイトル: なし + + <#if document.properties.description?exists> +説明: ${document.properties.description} + <#else> +説明: なし + +作成者: ${document.properties.creator} +作成日時: ${document.properties.created?datetime} +修正者: ${document.properties.modifier} +修正日時: ${document.properties.modified?datetime} +サイズ: ${document.size / 1024} KB + + +コンテンツリンク + +コンテンツ フォルダー: ${contextUrl}/navigate/browse${document.parent.webdavUrl} +コンテンツ URL: ${contextUrl}${document.url} +ダウンロード URL: ${contextUrl}${document.downloadUrl} +WebDAV URL: ${contextUrl}${document.webdavUrl} + + diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share.ftl new file mode 100644 index 0000000000..6061e54334 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share.ftl @@ -0,0 +1,26 @@ +------------------------------------------------------------------------------ +Document name: ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +Title: ${document.properties.title} + <#else> +Title: NONE + + <#if document.properties.description?exists> +Description: ${document.properties.description} + <#else> +Description: NONE + +Creator: ${document.properties.creator} +Created: ${document.properties.created?datetime} +Modifier: ${document.properties.modifier} +Modified: ${document.properties.modified?datetime} +Size: ${document.size / 1024} Kb + + +CONTENT LINKS + +Content folder: ${shareContextUrl}/page/site/${parentPathFromSites} +Content URL: ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name} +Download URL: ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name}?a=true diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_de.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_de.ftl new file mode 100644 index 0000000000..34dc76ab70 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_de.ftl @@ -0,0 +1,26 @@ +------------------------------------------------------------------------------ +Dokumentname: ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +Titel: ${document.properties.title} + <#else> +Titel: KEINER + + <#if document.properties.description?exists> +Beschreibung: ${document.properties.description} + <#else> +Beschreibung: KEINE + +Ersteller: ${document.properties.creator} +Erstellt am: ${document.properties.created?datetime} +Bearbeiter: ${document.properties.modifier} +Bearbeitet am: ${document.properties.modified?datetime} +Größe: ${document.size / 1024} Kb + + +Links zum Inhalt + +Dokumenten Ordner: ${shareContextUrl}/page/site/${parentPathFromSites} +URL zum Inhalt: ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name} +Download URL: ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name}?a=true diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_es.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_es.ftl new file mode 100644 index 0000000000..f3b73a4f56 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_es.ftl @@ -0,0 +1,26 @@ +------------------------------------------------------------------------------ +Nombre del documento: ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +Título: ${document.properties.title} + <#else> +Título: NINGUNO + + <#if document.properties.description?exists> +Descripción: ${document.properties.description} + <#else> +Descripción: NINGUNA + +Creador: ${document.properties.creator} +Creado: ${document.properties.created?datetime} +Modificador: ${document.properties.modifier} +Modificado: ${document.properties.modified?datetime} +Tamaño: ${document.size / 1024} Kb + + +Enlaces de contenido + +Carpeta de contenido: ${shareContextUrl}/page/site/${parentPathFromSites} +Dirección URL de contenido: ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name} +Dirección URL de descarga: ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name}?a=true diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_fr.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_fr.ftl new file mode 100644 index 0000000000..6710d95784 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_fr.ftl @@ -0,0 +1,26 @@ +------------------------------------------------------------------------------ +Nom du document : ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +Titre: ${document.properties.title} + <#else> +Titre: AUCUN + + <#if document.properties.description?exists> +Description: ${document.properties.description} + <#else> +Description: AUCUN + +Créateur: ${document.properties.creator} +Créé: ${document.properties.created?datetime} +Modificateur: ${document.properties.modifier} +Modifié: ${document.properties.modified?datetime} +Taille: ${document.size / 1024} Kb + + +Liens de contenu + +Dossier du contenu : ${shareContextUrl}/page/site/${parentPathFromSites} +URL de contenu : ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name} +Adresse de téléchargement : ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name}?a=true \ No newline at end of file diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_it.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_it.ftl new file mode 100644 index 0000000000..09053b3a93 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_it.ftl @@ -0,0 +1,26 @@ +------------------------------------------------------------------------------ +Nome documento: ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +Titolo: ${document.properties.title} + <#else> +Titolo: NESSUNO + + <#if document.properties.description?exists> +Descrizione: ${document.properties.description} + <#else> +Descrizione: NESSUNO + +Autore: ${document.properties.creator} +Data di creazione: ${document.properties.created?datetime} +Modificatore: ${document.properties.modifier} +Data di modifica: ${document.properties.modified?datetime} +Dimensioni: ${document.size / 1024} Kb + + +Collegamenti del contenuto + +Cartella del contenuto: ${shareContextUrl}/page/site/${parentPathFromSites} +URL del contenuto: ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name} +URL di download: ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name}?a=true diff --git a/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_ja.ftl b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_ja.ftl new file mode 100644 index 0000000000..572cb43959 --- /dev/null +++ b/config/alfresco/imap/imapSpacesTemplates/emailbody_textplain_share_ja.ftl @@ -0,0 +1,26 @@ +------------------------------------------------------------------------------ +ドキュメント名: ${document.name} +------------------------------------------------------------------------------ + + <#if document.properties.title?exists> +タイトル: ${document.properties.title} + <#else> +タイトル: なし + + <#if document.properties.description?exists> +説明: ${document.properties.description} + <#else> +説明: なし + +作成者: ${document.properties.creator} +作成日時: ${document.properties.created?datetime} +修正者: ${document.properties.modifier} +修正日時: ${document.properties.modified?datetime} +サイズ: ${document.size / 1024} Kb + + +コンテンツリンク + +コンテンツ フォルダー: ${shareContextUrl}/page/site/${parentPathFromSites} +コンテンツURL: ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name} +ダウンロード URL: ${shareContextUrl}/proxy/alfresco/api/node/content/${document.storeType}/${document.storeId}/${document.id}/${document.name}?a=true diff --git a/config/alfresco/import-export-context.xml b/config/alfresco/import-export-context.xml index 8ed9cadca5..be16752543 100644 --- a/config/alfresco/import-export-context.xml +++ b/config/alfresco/import-export-context.xml @@ -396,6 +396,7 @@ ${spaces.transfer_groups.childname} ${spaces.transfer_temp.childname} ${spaces.inbound_transfer_records.childname} + ${spaces.imap_attachments.childname} ${spaces.imap_templates.childname} ${spaces.emailActions.childname} ${spaces.searchAction.childname} @@ -684,16 +685,14 @@ alfresco/messages/bootstrap-spaces - /${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.imapConfig.childname}/${spaces.imap_templates.childname} - alfresco/bootstrap/imapSpacesTemplates.acp + alfresco/bootstrap/imapSpacesTemplates.xml alfresco/messages/bootstrap-spaces - ${publishing.root.path} alfresco/bootstrap/publishingRootFolder.xml diff --git a/config/alfresco/messages/bootstrap-spaces.properties b/config/alfresco/messages/bootstrap-spaces.properties index c6b7eee3db..a92e5b146c 100644 --- a/config/alfresco/messages/bootstrap-spaces.properties +++ b/config/alfresco/messages/bootstrap-spaces.properties @@ -6,6 +6,9 @@ spaces.company_home.description=The company root space spaces.dictionary.name=Data Dictionary spaces.dictionary.description=User managed definitions +spaces.imap_attachments.name=Imap Attachments +spaces.imap_attachments.description=Imap Attachments + spaces.imapConfig.name=Imap Configs spaces.imapConfig.description=Imap Configs diff --git a/config/alfresco/messages/bootstrap-spaces_ru.properties b/config/alfresco/messages/bootstrap-spaces_ru.properties index d2148a2241..0b0322d435 100755 --- a/config/alfresco/messages/bootstrap-spaces_ru.properties +++ b/config/alfresco/messages/bootstrap-spaces_ru.properties @@ -6,6 +6,9 @@ spaces.company_home.description=\u041A\u043E\u0440\u043D\u0435\u0432\u043E\u0435 spaces.dictionary.name=\u0421\u043B\u043E\u0432\u0430\u0440\u044C \u0434\u0430\u043D\u043D\u044B\u0445 spaces.dictionary.description=\u0423\u043F\u0440\u0430\u0432\u043B\u044F\u0435\u043C\u044B\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u043C \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u044F +spaces.imap_attachments.name=\u0412\u043B\u043E\u0436\u0435\u043D\u0438\u044F IMAP +spaces.imap_attachments.description=\u0412\u043B\u043E\u0436\u0435\u043D\u0438\u044F IMAP + spaces.imapConfig.name=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Imap spaces.imapConfig.description=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Imap diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 1f67fa5b3f..7c51c10819 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -2701,7 +2701,7 @@ /${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.imapConfig.childname}/${spaces.imap_templates.childname} - alfresco/bootstrap/imapSpacesTemplates.acp + alfresco/bootstrap/imapSpacesTemplates.xml alfresco/messages/bootstrap-spaces diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index 8a3b6054b7..c59a4c0760 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -397,6 +397,7 @@ spaces.company_home.childname=app:company_home spaces.guest_home.childname=app:guest_home spaces.dictionary.childname=app:dictionary spaces.templates.childname=app:space_templates +spaces.imap_attachments.childname=cm:Imap Attachments spaces.imapConfig.childname=app:imap_configs spaces.imap_templates.childname=app:imap_templates spaces.scheduled_actions.childname=cm:Scheduled Actions @@ -742,7 +743,7 @@ imap.server.attachments.extraction.enabled=true imap.attachments.mode=SEPARATE imap.attachments.folder.store=${spaces.store} imap.attachments.folder.rootPath=/${spaces.company_home.childname} -imap.attachments.folder.folderPath=Imap Attachments +imap.attachments.folder.folderPath=${spaces.imap_attachments.childname} # Activities Feed - refer to subsystem diff --git a/config/alfresco/subsystems/Authentication/common-ldap-context.xml b/config/alfresco/subsystems/Authentication/common-ldap-context.xml index bbd9118ae1..a9ab794413 100644 --- a/config/alfresco/subsystems/Authentication/common-ldap-context.xml +++ b/config/alfresco/subsystems/Authentication/common-ldap-context.xml @@ -111,6 +111,11 @@ ${ldap.authentication.java.naming.security.authentication} + + + ${ldap.authentication.java.naming.read.timeout} + + follow @@ -160,6 +165,11 @@ true + + + ${ldap.authentication.java.naming.read.timeout} + + follow diff --git a/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties b/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties index f9fa167220..d98bc9cf77 100644 --- a/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties +++ b/config/alfresco/subsystems/Authentication/ldap-ad/ldap-ad-authentication.properties @@ -117,4 +117,7 @@ ldap.synchronization.personType=user ldap.synchronization.groupMemberAttributeName=member # If true progress estimation is enabled. When enabled, the user query has to be run twice in order to count entries. -ldap.synchronization.enableProgressEstimation=true \ No newline at end of file +ldap.synchronization.enableProgressEstimation=true + +# Requests timeout, in miliseconds, use 0 for none (default) +ldap.authentication.java.naming.read.timeout=0 \ No newline at end of file diff --git a/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties index 882eb80e9a..3fde29c01e 100644 --- a/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties +++ b/config/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties @@ -123,4 +123,7 @@ ldap.synchronization.personType=inetOrgPerson ldap.synchronization.groupMemberAttributeName=member # If true progress estimation is enabled. When enabled, the user query has to be run twice in order to count entries. -ldap.synchronization.enableProgressEstimation=true \ No newline at end of file +ldap.synchronization.enableProgressEstimation=true + +# Requests timeout, in miliseconds, use 0 for none (default) +ldap.authentication.java.naming.read.timeout=0 \ No newline at end of file diff --git a/config/alfresco/thumbnail-service-context.xml b/config/alfresco/thumbnail-service-context.xml index e8bcc6f4b7..191861733e 100644 --- a/config/alfresco/thumbnail-service-context.xml +++ b/config/alfresco/thumbnail-service-context.xml @@ -131,8 +131,8 @@ - - + + diff --git a/pom.xml b/pom.xml index 871f4abeff..fe22e0eab1 100644 --- a/pom.xml +++ b/pom.xml @@ -8,14 +8,14 @@ Alfresco Repository alfresco-parent - org.alfresco + org.alfresco.enterprise 4.2-SNAPSHOT ../../pom-experimental.xml - org.alfresco + org.alfresco.enterprise alfresco-data-model ${project.version} @@ -30,17 +30,17 @@ - org.alfresco + org.alfresco.enterprise alfresco-deployment ${project.version} - org.alfresco + org.alfresco.enterprise alfresco-jlan ${project.version} - org.alfresco + org.alfresco.enterprise alfresco-mbeans ${project.version} @@ -723,14 +723,14 @@ test - org.alfresco + org.alfresco.enterprise alfresco-deployment ${project.version} tests test - org.alfresco + org.alfresco.enterprise alfresco-data-model ${project.version} tests diff --git a/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java b/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java index d75280b113..0095f8bb40 100644 --- a/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java +++ b/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2011 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -669,7 +669,17 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware, CMISPropertyDefinition propDef = cmisDictionaryService.findPropertyByQueryName(sort[0]); if (propDef != null) { - QName sortProp = propDef.getPropertyAccessor().getMappedProperty(); + QName sortProp = null; + if (propDef.getPropertyId().getId().equals(CMISDictionaryModel.PROP_BASE_TYPE_ID)) + { + // special-case (see also ALF-13968) - for getChildren, using "cmis:baseTypeId" allows sorting of folders first and vice-versa (cmis:folder <-> cmis:document) + sortProp = GetChildrenCannedQuery.SORT_QNAME_NODE_IS_FOLDER; + } + else + { + sortProp = propDef.getPropertyAccessor().getMappedProperty(); + } + if (sortProp != null) { boolean sortAsc = (sort.length == 1) || sort[1].equalsIgnoreCase("asc"); diff --git a/source/java/org/alfresco/filesys/repo/LegacyFileStateDriver.java b/source/java/org/alfresco/filesys/repo/LegacyFileStateDriver.java index 3dd4f32280..e2279e3ed6 100644 --- a/source/java/org/alfresco/filesys/repo/LegacyFileStateDriver.java +++ b/source/java/org/alfresco/filesys/repo/LegacyFileStateDriver.java @@ -327,6 +327,7 @@ public class LegacyFileStateDriver implements ExtendedDiskInterface logger.debug("close file, release access token:" + token); } cache.releaseFileAccess(fstate, token); + } if(fstate.getOpenCount() == 0 ) @@ -337,6 +338,10 @@ public class LegacyFileStateDriver implements ExtendedDiskInterface fstate.updateChangeDateTime(0); fstate.updateModifyDateTime(0); } + + // Clear the access token + + param.setAccessToken( null); } } catch(IOException ie) diff --git a/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java b/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java index 181a0f75b3..68ab783b7b 100644 --- a/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java +++ b/source/java/org/alfresco/opencmis/AlfrescoCmisServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2011 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -39,6 +39,7 @@ import javax.servlet.http.HttpServletRequest; import net.sf.acegisecurity.Authentication; +import org.alfresco.cmis.CMISDictionaryModel; import org.alfresco.cmis.CMISInvalidArgumentException; import org.alfresco.model.ContentModel; import org.alfresco.opencmis.dictionary.CMISNodeInfo; @@ -500,14 +501,24 @@ public class AlfrescoCmisServiceImpl extends AbstractCmisService implements Alfr for (int i = 0; i < len; i++) { String[] sort = parts[i].split(" +"); - + if (sort.length > 0) { PropertyDefinitionWrapper propDef = connector.getOpenCMISDictionaryService() .findPropertyByQueryName(sort[0]); if (propDef != null) { - QName sortProp = propDef.getPropertyAccessor().getMappedProperty(); + QName sortProp = null; + if (propDef.getPropertyId().equals(CMISDictionaryModel.PROP_BASE_TYPE_ID)) + { + // special-case (see also ALF-13968) - for getChildren, using "cmis:baseTypeId" allows sorting of folders first and vice-versa (cmis:folder <-> cmis:document) + sortProp = GetChildrenCannedQuery.SORT_QNAME_NODE_IS_FOLDER; + } + else + { + sortProp = propDef.getPropertyAccessor().getMappedProperty(); + } + if (sortProp != null) { boolean sortAsc = (sort.length == 1) || sort[1].equalsIgnoreCase("asc"); diff --git a/source/java/org/alfresco/repo/action/executer/CheckOutActionExecuterTest.java b/source/java/org/alfresco/repo/action/executer/CheckOutActionExecuterTest.java new file mode 100644 index 0000000000..64d242e3e7 --- /dev/null +++ b/source/java/org/alfresco/repo/action/executer/CheckOutActionExecuterTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.action.executer; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.action.ActionImpl; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.service.cmr.coci.CheckOutCheckInService; +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.namespace.QName; +import org.alfresco.util.BaseSpringTest; +import org.alfresco.util.GUID; + +/** + * Tests checkout using action executer + */ +public class CheckOutActionExecuterTest extends BaseSpringTest +{ + private NodeService nodeService; + private CheckOutCheckInService checkOutCheckInService; + + /** + * The add features action executer + */ + private CheckOutActionExecuter executer; + + private StoreRef testStoreRef; + private NodeRef rootNodeRef; + private NodeRef nodeRefContent; + private NodeRef nodeRefFolder; + + /** + * Id used to identify the test action created + */ + private final static String ID = GUID.generate(); + + @Override + protected void onSetUpInTransaction() throws Exception + { + this.nodeService = (NodeService) this.applicationContext.getBean("nodeService"); + + this.checkOutCheckInService = (CheckOutCheckInService) this.applicationContext.getBean("checkOutCheckInService"); + + AuthenticationComponent authenticationComponent = (AuthenticationComponent) applicationContext.getBean("authenticationComponent"); + authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); + + // Create the store and get the root node + this.testStoreRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis()); + this.rootNodeRef = this.nodeService.getRootNode(this.testStoreRef); + + // Create 'content' the node used for tests + this.nodeRefContent = this.nodeService.createNode( + this.rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName("{test}contenttestnode"), + ContentModel.TYPE_CONTENT).getChildRef(); + + // Create 'folder' the node used for tests + this.nodeRefFolder = this.nodeService.createNode( + this.rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName("{test}foldertestnode"), + ContentModel.TYPE_FOLDER).getChildRef(); + + // Get the executer instance + this.executer = (CheckOutActionExecuter) this.applicationContext.getBean(CheckOutActionExecuter.NAME); + } + + /** + * Test execution + */ + public void testExecution() + { + // Execute the action + ActionImpl action = new ActionImpl(null, ID, CheckOutActionExecuter.NAME, null); + + // Execute check out action for 'content' node + this.executer.execute(action, this.nodeRefContent); + // Execute check out action for 'folder' node + this.executer.execute(action, this.nodeRefFolder); + + assertNotNull(this.checkOutCheckInService.getWorkingCopy(this.nodeRefContent)); + assertNull(this.checkOutCheckInService.getWorkingCopy(this.nodeRefFolder)); + } +} diff --git a/source/java/org/alfresco/repo/activities/ActivityPostServiceImpl.java b/source/java/org/alfresco/repo/activities/ActivityPostServiceImpl.java index 2fcb167c1f..ae9b3f5503 100644 --- a/source/java/org/alfresco/repo/activities/ActivityPostServiceImpl.java +++ b/source/java/org/alfresco/repo/activities/ActivityPostServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2011 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -41,6 +41,7 @@ import org.springframework.extensions.surf.util.ParameterCheck; * Activity Post Service Implementation * * @author janv + * @since 3.0 */ public class ActivityPostServiceImpl implements ActivityPostService { @@ -188,6 +189,17 @@ public class ActivityPostServiceImpl implements ActivityPostService activityData = jo.toString(); } checkNodeRef(jo); + + // ALF-10362 - belts-and-braces (note: Share sets "title" from cm:name) + if (jo.has(PostLookup.JSON_TITLE)) + { + String title = jo.getString(PostLookup.JSON_TITLE); + if (title.length() > ActivityPostDAO.MAX_LEN_NAME) + { + jo.put(PostLookup.JSON_TITLE, title.substring(0, 255)); + activityData = jo.toString(); + } + } } } catch (JSONException e) @@ -196,7 +208,6 @@ public class ActivityPostServiceImpl implements ActivityPostService // According to test data in org/alfresco/repo/activities/script/test_activityService.js // invalid JSON should be OK. } - if (activityData.length() > ActivityPostDAO.MAX_LEN_ACTIVITY_DATA) { diff --git a/source/java/org/alfresco/repo/activities/ActivityServiceImplTest.java b/source/java/org/alfresco/repo/activities/ActivityServiceImplTest.java index f2e60ff008..3892bf6948 100644 --- a/source/java/org/alfresco/repo/activities/ActivityServiceImplTest.java +++ b/source/java/org/alfresco/repo/activities/ActivityServiceImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -18,9 +18,14 @@ */ package org.alfresco.repo.activities; +import java.util.Arrays; import java.util.HashMap; import java.util.List; +import junit.framework.TestCase; + +import org.alfresco.repo.domain.activities.ActivityPostDAO; +import org.alfresco.repo.domain.activities.ActivityPostEntity; import org.alfresco.repo.jscript.ClasspathScriptLocation; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.activities.ActivityService; @@ -31,58 +36,66 @@ import org.alfresco.service.cmr.repository.ScriptService; import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; -import org.alfresco.util.BaseSpringTest; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.context.ApplicationContext; /** * Activity Service Implementation unit test * * @author janv + * @since 3.0 */ -public class ActivityServiceImplTest extends BaseSpringTest +public class ActivityServiceImplTest extends TestCase { + private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + private ActivityService activityService; private ScriptService scriptService; private MutableAuthenticationService authenticationService; private SiteService siteService; + private ActivityPostDAO postDAO; private static final String ADMIN_PW = "admin"; private static final String USER_UN = "bob"; private static final String USER_PW = "bob"; - protected void onSetUpInTransaction() throws Exception + private static final String TEST_RUN_ID = ""+System.currentTimeMillis(); + + @Override + protected void setUp() throws Exception { - super.onSetUpInTransaction(); + activityService = (ActivityService)ctx.getBean("activityService"); + scriptService = (ScriptService)ctx.getBean("ScriptService"); + siteService = (SiteService)ctx.getBean("SiteService"); - // Get the required services - this.activityService = (ActivityService)this.applicationContext.getBean("activityService"); - this.scriptService = (ScriptService)this.applicationContext.getBean("ScriptService"); - this.siteService = (SiteService)this.applicationContext.getBean("SiteService"); + postDAO = (ActivityPostDAO)ctx.getBean("postDAO"); - this.authenticationService = (MutableAuthenticationService)applicationContext.getBean("authenticationService"); + authenticationService = (MutableAuthenticationService)ctx.getBean("AuthenticationService"); authenticationService.authenticate(AuthenticationUtil.getAdminUserName(), ADMIN_PW.toCharArray()); } - protected void onTearDownInTransaction() throws Exception + @Override + protected void tearDown() throws Exception { authenticationService.clearCurrentSecurityContext(); } - + public void testPostValidActivities() throws Exception { - this.activityService.postActivity("org.alfresco.testActivityType1", null, null, ""); + activityService.postActivity("org.alfresco.testActivityType1", null, null, ""); - this.activityService.postActivity("org.alfresco.testActivityType2", "", "", ""); + activityService.postActivity("org.alfresco.testActivityType2", "", "", ""); - this.activityService.postActivity("org.alfresco.testActivityType3", "site1", "appToolA", "{ \"var1\" : \"val1\" }"); + activityService.postActivity("org.alfresco.testActivityType3", "site1", "appToolA", "{ \"var1\" : \"val1\" }"); } public void testPostInvalidActivities() throws Exception { try { - this.activityService.postActivity("", "", "",(NodeRef) null, ""); + activityService.postActivity("", "", "",(NodeRef) null, ""); fail("invalid post activity"); } catch (IllegalArgumentException iae) @@ -92,7 +105,7 @@ public class ActivityServiceImplTest extends BaseSpringTest try { - this.activityService.postActivity("", "", "", ""); + activityService.postActivity("", "", "", ""); fail("invalid post activity"); } catch (IllegalArgumentException iae) @@ -102,56 +115,59 @@ public class ActivityServiceImplTest extends BaseSpringTest try { - this.activityService.postActivity("org.alfresco.testActivityType1", "", "", "{ \"nodeRef\" : \"notfound\" }"); + activityService.postActivity("org.alfresco.testActivityType1", "", "", "{ \"nodeRef\" : \"notfound\" }"); fail("invalid post activity: bad nodeRef"); } catch (IllegalArgumentException iae) { assertTrue(iae.getMessage().contains("Invalid node ref: notfound")); } - } - + } + public void testGetEmptySiteFeed() throws Exception { - authenticationService.clearCurrentSecurityContext(); - if(! authenticationService.authenticationExists(USER_UN)) { authenticationService.createAuthentication(USER_UN, USER_PW.toCharArray()); } + + authenticationService.clearCurrentSecurityContext(); + authenticationService.authenticate(USER_UN, USER_PW.toCharArray()); - siteService.createSite("mypreset", "emptySite", "empty site title", "empty site description", SiteVisibility.PUBLIC); + String siteId = "emptySite-"+TEST_RUN_ID; + siteService.createSite("mypreset", siteId, "empty site title", "empty site description", SiteVisibility.PUBLIC); - List siteFeedEntries = this.activityService.getSiteFeedEntries("emptySite", "json"); + List siteFeedEntries = activityService.getSiteFeedEntries(siteId, "json"); assertNotNull(siteFeedEntries); assertTrue(siteFeedEntries.isEmpty()); + siteService.deleteSite(siteId); } public void testGetEmptyUserFeed() throws Exception { - List userFeedEntries = this.activityService.getUserFeedEntries("unknown user", "a format", null); + List userFeedEntries = activityService.getUserFeedEntries("unknown user", "a format", null); assertNotNull(userFeedEntries); assertTrue(userFeedEntries.isEmpty()); - userFeedEntries = this.activityService.getUserFeedEntries("unknown user", "a format", "some site"); + userFeedEntries = activityService.getUserFeedEntries("unknown user", "a format", "some site"); assertNotNull(userFeedEntries); assertTrue(userFeedEntries.isEmpty()); - userFeedEntries = this.activityService.getUserFeedEntries("unknown user", "a format", "some site", true, false, null, null); + userFeedEntries = activityService.getUserFeedEntries("unknown user", "a format", "some site", true, false, null, null); assertNotNull(userFeedEntries); assertTrue(userFeedEntries.isEmpty()); - userFeedEntries = this.activityService.getUserFeedEntries("unknown user", "a format", "some site", false, true, null, null); + userFeedEntries = activityService.getUserFeedEntries("unknown user", "a format", "some site", false, true, null, null); assertNotNull(userFeedEntries); assertTrue(userFeedEntries.isEmpty()); - userFeedEntries = this.activityService.getUserFeedEntries("unknown user", "a format", "some site", true, true, null, null); + userFeedEntries = activityService.getUserFeedEntries("unknown user", "a format", "some site", true, true, null, null); assertNotNull(userFeedEntries); assertTrue(userFeedEntries.isEmpty()); @@ -171,47 +187,63 @@ public class ActivityServiceImplTest extends BaseSpringTest public void testFeedControls() throws Exception { - List feedControls = this.activityService.getFeedControls(USER_UN); + List feedControls = activityService.getFeedControls(USER_UN); assertNotNull(feedControls); assertTrue(feedControls.isEmpty()); - - authenticationService.clearCurrentSecurityContext(); if(! authenticationService.authenticationExists(USER_UN)) { authenticationService.createAuthentication(USER_UN, USER_PW.toCharArray()); } + + authenticationService.clearCurrentSecurityContext(); + authenticationService.authenticate(USER_UN, USER_PW.toCharArray()); - feedControls = this.activityService.getFeedControls(); + feedControls = activityService.getFeedControls(); assertNotNull(feedControls); assertTrue(feedControls.isEmpty()); - assertFalse(this.activityService.existsFeedControl(new FeedControl("mySite1", "appTool1"))); + assertFalse(activityService.existsFeedControl(new FeedControl("mySite1", "appTool1"))); - this.activityService.setFeedControl(new FeedControl("mySite1", null)); - this.activityService.setFeedControl(new FeedControl("mySite1", "appTool1")); - this.activityService.setFeedControl(new FeedControl(null, "appTool2")); + activityService.setFeedControl(new FeedControl("mySite1", null)); + activityService.setFeedControl(new FeedControl("mySite1", "appTool1")); + activityService.setFeedControl(new FeedControl(null, "appTool2")); - feedControls = this.activityService.getFeedControls(); + feedControls = activityService.getFeedControls(); assertEquals(3, feedControls.size()); - feedControls = this.activityService.getFeedControls(USER_UN); + feedControls = activityService.getFeedControls(USER_UN); assertEquals(3, feedControls.size()); - assertTrue(this.activityService.existsFeedControl(new FeedControl("mySite1", "appTool1"))); + assertTrue(activityService.existsFeedControl(new FeedControl("mySite1", "appTool1"))); - this.activityService.unsetFeedControl(new FeedControl("mySite1", "appTool1")); + activityService.unsetFeedControl(new FeedControl("mySite1", "appTool1")); - assertFalse(this.activityService.existsFeedControl(new FeedControl("mySite1", "appTool1"))); + assertFalse(activityService.existsFeedControl(new FeedControl("mySite1", "appTool1"))); - feedControls = this.activityService.getFeedControls(); + feedControls = activityService.getFeedControls(); assertEquals(2, feedControls.size()); - this.activityService.unsetFeedControl(new FeedControl("mySite1", null)); - this.activityService.unsetFeedControl(new FeedControl(null, "appTool2")); + activityService.unsetFeedControl(new FeedControl("mySite1", null)); + activityService.unsetFeedControl(new FeedControl(null, "appTool2")); - feedControls = this.activityService.getFeedControls(); + feedControls = activityService.getFeedControls(); assertEquals(0, feedControls.size()); } + + public void testLongName_ALF_10362() throws Exception + { + byte [] namePattern = new byte[1024]; + Arrays.fill(namePattern, (byte) 'A'); + + ActivityPostEntity params = new ActivityPostEntity(); + params.setStatus(ActivityPostEntity.STATUS.PENDING.toString()); + + int cnt = postDAO.selectPosts(params).size(); + + activityService.postActivity("org.alfresco.testActivityType4", "site2", "appToolA", "{\"title\":\"" + new String(namePattern, "UTF-8") + "\"}"); + + assertEquals(cnt+1, postDAO.selectPosts(params).size()); + } } diff --git a/source/java/org/alfresco/repo/admin/patch/impl/CopiedFromAspectPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/CopiedFromAspectPatch.java index 8dd4b04140..6fcab4f8e6 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/CopiedFromAspectPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/CopiedFromAspectPatch.java @@ -448,13 +448,26 @@ public class CopiedFromAspectPatch extends AbstractPatch } else { - if (logger.isDebugEnabled()) + QName sourceTypeQName = nodeService.getType(sourceNodeRef); + // cm:copiedfrom target must be a cm:object + if (dictionaryService.isSubClass(sourceTypeQName, ContentModel.TYPE_CMOBJECT)) { - logger.debug("\tP: Adding association cm:original: " + nodePair); + if (logger.isDebugEnabled()) + { + logger.debug("\tP: Adding association cm:original: " + nodePair); + } + writeLine(file, "Adding association cm:original: " + nodePair); + nodeService.createAssociation(nodeRef, sourceNodeRef, ContentModel.ASSOC_ORIGINAL); + } + else + { + if (logger.isDebugEnabled()) + { + logger.debug("\tP: Removing incompatible aspect cm:copiedfrom " + nodePair); + } + writeLine(file, "Removing incompatible aspect cm:copiedfrom " + nodePair); + nodeService.removeAspect(nodeRef, ContentModel.ASPECT_COPIEDFROM); } - writeLine(file, "Adding association cm:original: " + nodePair); - // Create the association - nodeService.createAssociation(nodeRef, sourceNodeRef, ContentModel.ASSOC_ORIGINAL); } } if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY)) diff --git a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java index c6f78684df..df4ba6d8ea 100644 --- a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java +++ b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java @@ -34,7 +34,6 @@ import org.alfresco.repo.coci.CheckOutCheckInServicePolicies.BeforeCheckOut; import org.alfresco.repo.coci.CheckOutCheckInServicePolicies.OnCancelCheckOut; import org.alfresco.repo.coci.CheckOutCheckInServicePolicies.OnCheckIn; import org.alfresco.repo.coci.CheckOutCheckInServicePolicies.OnCheckOut; -import org.alfresco.repo.lock.LockUtils; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.ClassPolicyDelegate; import org.alfresco.repo.policy.PolicyComponent; @@ -42,6 +41,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.coci.CheckOutCheckInServiceException; import org.alfresco.service.cmr.lock.LockService; +import org.alfresco.service.cmr.lock.LockStatus; import org.alfresco.service.cmr.lock.LockType; import org.alfresco.service.cmr.lock.NodeLockedException; import org.alfresco.service.cmr.lock.UnableToReleaseLockException; @@ -377,7 +377,8 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService // It is not enough to check LockUtils.isLockedOrReadOnly in case when the same user does offline and online edit (for instance in two open browsers). In this case we get // set ContentModel.ASPECT_LOCKABLE and LockType.WRITE_LOCK. So, here we have to check following - if (lockService.getLockType(nodeRef) == LockType.WRITE_LOCK) + LockStatus lockStatus = lockService.getLockStatus(nodeRef); + if (lockStatus != LockStatus.NO_LOCK && lockStatus != LockStatus.LOCK_EXPIRED) { throw new NodeLockedException(nodeRef); } diff --git a/source/java/org/alfresco/repo/content/ContentServiceImpl.java b/source/java/org/alfresco/repo/content/ContentServiceImpl.java index ca9edefda2..1c914f7da0 100644 --- a/source/java/org/alfresco/repo/content/ContentServiceImpl.java +++ b/source/java/org/alfresco/repo/content/ContentServiceImpl.java @@ -295,7 +295,17 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa } // Check for new content - isNewContent = !hasContentBefore && hasContentAfter; + isNewContent = isNewContent || !hasContentBefore && hasContentAfter; + + // Make it clear when there's no content before or after + if (!hasContentBefore) + { + beforeValue = null; + } + if (!hasContentAfter) + { + afterValue = null; + } // So debug ... if (logger.isDebugEnabled()) diff --git a/source/java/org/alfresco/repo/domain/activities/ActivityPostDAO.java b/source/java/org/alfresco/repo/domain/activities/ActivityPostDAO.java index b68ab3792e..28d060f10e 100644 --- a/source/java/org/alfresco/repo/domain/activities/ActivityPostDAO.java +++ b/source/java/org/alfresco/repo/domain/activities/ActivityPostDAO.java @@ -1,19 +1,19 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ package org.alfresco.repo.domain.activities; @@ -24,15 +24,20 @@ import java.util.List; /** * Interface for activity post DAO service + * + * @author janv + * @since 3.0 */ public interface ActivityPostDAO extends ActivitiesDAO { public static final int MAX_LEN_USER_ID = 255; // needs to match schema: feed_user_id, post_user_id public static final int MAX_LEN_SITE_ID = 255; // needs to match schema: site_network public static final int MAX_LEN_ACTIVITY_TYPE = 255; // needs to match schema: activity_type - public static final int MAX_LEN_ACTIVITY_DATA = 4000; // needs to match schema: activity_data + public static final int MAX_LEN_ACTIVITY_DATA = 1024; // needs to match schema: activity_data public static final int MAX_LEN_APP_TOOL_ID = 36; // needs to match schema: app_tool + public static final int MAX_LEN_NAME = 255; // eg. filename + public List selectPosts(ActivityPostEntity activityPost) throws SQLException; public Long getMaxActivitySeq() throws SQLException; diff --git a/source/java/org/alfresco/repo/domain/solr/NodeParametersEntity.java b/source/java/org/alfresco/repo/domain/solr/NodeParametersEntity.java index 37ed529498..a74cadd7d3 100644 --- a/source/java/org/alfresco/repo/domain/solr/NodeParametersEntity.java +++ b/source/java/org/alfresco/repo/domain/solr/NodeParametersEntity.java @@ -48,7 +48,7 @@ public class NodeParametersEntity extends NodeParameters */ public NodeParametersEntity(QNameDAO qnameDAO) { - Pair qnamePair = qnameDAO.getOrCreateQName(ContentModel.PROP_ORIGINAL_ID); + Pair qnamePair = qnameDAO.getQName(ContentModel.PROP_ORIGINAL_ID); this.setOriginalIdPropQNameId(qnamePair == null ? -1 : qnamePair.getFirst()); } diff --git a/source/java/org/alfresco/repo/imap/ImapMessageTest.java b/source/java/org/alfresco/repo/imap/ImapMessageTest.java index a31888d09e..207eaf54e0 100644 --- a/source/java/org/alfresco/repo/imap/ImapMessageTest.java +++ b/source/java/org/alfresco/repo/imap/ImapMessageTest.java @@ -200,7 +200,7 @@ public class ImapMessageTest extends TestCase RepositoryFolderConfigBean imapHome = new RepositoryFolderConfigBean(); imapHome.setStore(storePath); imapHome.setRootPath(companyHomePathInStore); - imapHome.setFolderPath(IMAP_FOLDER_NAME); + imapHome.setFolderPath(NamespaceService.CONTENT_MODEL_PREFIX + ":" + IMAP_FOLDER_NAME); imapServiceImpl.setImapHome(imapHome); diff --git a/source/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java b/source/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java index c225d73ad4..cc416f472f 100644 --- a/source/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java +++ b/source/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java @@ -91,7 +91,7 @@ public class ImapServiceImplCacheTest extends TestCase RepositoryFolderConfigBean imapHome = new RepositoryFolderConfigBean(); imapHome.setStore(storePath); imapHome.setRootPath(companyHomePathInStore); - imapHome.setFolderPath(TEST_IMAP_FOLDER_NAME); + imapHome.setFolderPath(NamespaceService.CONTENT_MODEL_PREFIX + ":" + TEST_IMAP_FOLDER_NAME); imapServiceImpl.setImapHome(imapHome); // Starting IMAP diff --git a/source/java/org/alfresco/repo/imap/ImapServiceImplTest.java b/source/java/org/alfresco/repo/imap/ImapServiceImplTest.java index 7e0af369cd..829a43c428 100644 --- a/source/java/org/alfresco/repo/imap/ImapServiceImplTest.java +++ b/source/java/org/alfresco/repo/imap/ImapServiceImplTest.java @@ -176,7 +176,7 @@ public class ImapServiceImplTest extends TestCase RepositoryFolderConfigBean imapHome = new RepositoryFolderConfigBean(); imapHome.setStore(storePath); imapHome.setRootPath(companyHomePathInStore); - imapHome.setFolderPath(TEST_IMAP_FOLDER_NAME); + imapHome.setFolderPath(NamespaceService.CONTENT_MODEL_PREFIX + ":" + TEST_IMAP_FOLDER_NAME); imapServiceImpl.setImapHome(imapHome); // Starting IMAP diff --git a/source/java/org/alfresco/repo/jscript/ScriptNode.java b/source/java/org/alfresco/repo/jscript/ScriptNode.java index 7104a7cd2a..28a578f8c5 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptNode.java +++ b/source/java/org/alfresco/repo/jscript/ScriptNode.java @@ -51,6 +51,7 @@ import org.alfresco.repo.action.executer.TransformActionExecuter; import org.alfresco.repo.content.transform.UnimportantTransformException; import org.alfresco.repo.content.transform.magick.ImageTransformationOptions; import org.alfresco.repo.model.filefolder.FileFolderServiceImpl.InvalidTypeException; +import org.alfresco.repo.node.getchildren.GetChildrenCannedQuery; import org.alfresco.repo.search.QueryParameterDefImpl; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; @@ -680,10 +681,14 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider ignoreTypeQNames.add(createQName(ignoreTypes.toString())); } - List> sortProps = null; // note: null sortProps => get all in default sort order + // ALF-13968 - sort folders before files (for Share) - TODO should be optional sort param + List> sortProps = new ArrayList>(2); + if ((sortProp == null) || (! sortProp.equals(GetChildrenCannedQuery.SORT_QNAME_NODE_TYPE.getLocalName()))) + { + sortProps.add(new Pair(GetChildrenCannedQuery.SORT_QNAME_NODE_IS_FOLDER, false)); + } if (sortProp != null) { - sortProps = new ArrayList>(1); sortProps.add(new Pair(createQName(sortProp), sortAsc)); } diff --git a/source/java/org/alfresco/repo/lock/LockUtils.java b/source/java/org/alfresco/repo/lock/LockUtils.java index 5bf37fbb87..f93b46f8e0 100644 --- a/source/java/org/alfresco/repo/lock/LockUtils.java +++ b/source/java/org/alfresco/repo/lock/LockUtils.java @@ -27,17 +27,25 @@ public class LockUtils { /** - * Indicates if the node is unlocked or the current user has a WRITE_LOCK

+ * Indicates if the node is locked AND it's not a WRITE_LOCK for the current user.

* * Ideally this would be a new method on the lockService, but cannot do this at the moment, * as this method is being added as part of a hot fix, so a public service cannot change * as the RM AMP might be installed and it has its own security context which would also need * to reflect this change. */ - public static boolean isLockedOrReadOnly(NodeRef nodeRef, LockService lockService) + public static boolean isLockedAndReadOnly(NodeRef nodeRef, LockService lockService) { LockStatus lockStatus = lockService.getLockStatus(nodeRef); - LockType lockType = lockService.getLockType(nodeRef); - return ! (lockStatus == LockStatus.NO_LOCK || (lockStatus == LockStatus.LOCK_OWNER && lockType == LockType.WRITE_LOCK)); + switch (lockStatus) + { + case NO_LOCK: + case LOCK_EXPIRED: + return false; + case LOCK_OWNER: + return lockService.getLockType(nodeRef) != LockType.WRITE_LOCK; + default: + return true; + } } } diff --git a/source/java/org/alfresco/repo/model/filefolder/GetChildrenCannedQuery.java b/source/java/org/alfresco/repo/model/filefolder/GetChildrenCannedQuery.java index 2b84bfce40..30e157cf94 100644 --- a/source/java/org/alfresco/repo/model/filefolder/GetChildrenCannedQuery.java +++ b/source/java/org/alfresco/repo/model/filefolder/GetChildrenCannedQuery.java @@ -18,8 +18,12 @@ */ package org.alfresco.repo.model.filefolder; +import java.io.Serializable; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import org.alfresco.model.ContentModel; import org.alfresco.query.CannedQueryParameters; import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.domain.node.NodePropertyHelper; @@ -30,7 +34,9 @@ import org.alfresco.repo.node.getchildren.FilterProp; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityBean; import org.alfresco.repo.tenant.TenantService; +import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; import org.alfresco.util.FileFilterMode; import org.alfresco.util.FileFilterMode.Client; @@ -43,13 +49,14 @@ import org.alfresco.util.FileFilterMode.Client; * This is the same as the nodes getchildren canned query, except it takes into account hidden files and folders. * * @since 4.1.1 - * @author steveglover + * @author steveglover, janv * */ public class GetChildrenCannedQuery extends org.alfresco.repo.node.getchildren.GetChildrenCannedQuery { private HiddenAspect hiddenAspect; - + private DictionaryService dictionaryService; + public GetChildrenCannedQuery( NodeDAO nodeDAO, QNameDAO qnameDAO, @@ -58,12 +65,15 @@ public class GetChildrenCannedQuery extends org.alfresco.repo.node.getchildren.G TenantService tenantService, MethodSecurityBean methodSecurity, CannedQueryParameters params, - HiddenAspect hiddenAspect) + HiddenAspect hiddenAspect, + DictionaryService dictionaryService) { - super(nodeDAO, qnameDAO, cannedQueryDAO, nodePropertyHelper, tenantService, methodSecurity, params); - this.hiddenAspect = hiddenAspect; + super(nodeDAO, qnameDAO, cannedQueryDAO, nodePropertyHelper, tenantService, methodSecurity, params); + + this.hiddenAspect = hiddenAspect; + this.dictionaryService = dictionaryService; } - + @Override protected UnsortedChildQueryCallback getUnsortedChildQueryCallback(final List rawResult, final int requestedCount) { @@ -80,29 +90,54 @@ public class GetChildrenCannedQuery extends org.alfresco.repo.node.getchildren.G private class FileFolderFilterSortChildQueryCallback extends DefaultFilterSortChildQueryCallback { - public FileFolderFilterSortChildQueryCallback(List children, List filterProps) - { - super(children, filterProps); - } - - @Override - protected boolean include(FilterSortNode node) - { - boolean ret = super.include(node); - + private Map isTypeFolderMap = new HashMap(10); + + public FileFolderFilterSortChildQueryCallback(List children, List filterProps) + { + super(children, filterProps); + } + + @Override + protected boolean include(FilterSortNode node) + { + boolean ret = super.include(node); + // only visible files are returned, relative to the client type. - try - { - final Client client = FileFilterMode.getClient(); - return ret && hiddenAspect.getVisibility(client, node.getNodeRef()) != Visibility.NotVisible; + try + { + final Client client = FileFilterMode.getClient(); + return ret && hiddenAspect.getVisibility(client, node.getNodeRef()) != Visibility.NotVisible; } catch(AccessDeniedException e) { - // user may not have permission to determine the visibility of the node - return ret; + // user may not have permission to determine the visibility of the node + return ret; } - } - + } + + @Override + public boolean handle(FilterSortNode node) + { + super.handle(node); + + Map propVals = node.getPropVals(); + QName nodeTypeQName = (QName)propVals.get(GetChildrenCannedQuery.SORT_QNAME_NODE_TYPE); + + if (nodeTypeQName != null) + { + // ALF-13968 + Boolean isFolder = isTypeFolderMap.get(nodeTypeQName); + if (isFolder == null) + { + isFolder = dictionaryService.isSubClass(nodeTypeQName, ContentModel.TYPE_FOLDER); + isTypeFolderMap.put(nodeTypeQName, isFolder); + } + + propVals.put(GetChildrenCannedQuery.SORT_QNAME_NODE_IS_FOLDER, isFolder); + } + + return true; + } } private class FileFolderUnsortedChildQueryCallback extends DefaultUnsortedChildQueryCallback diff --git a/source/java/org/alfresco/repo/model/filefolder/GetChildrenCannedQueryFactory.java b/source/java/org/alfresco/repo/model/filefolder/GetChildrenCannedQueryFactory.java index b72a33e3a5..5ac6871c27 100644 --- a/source/java/org/alfresco/repo/model/filefolder/GetChildrenCannedQueryFactory.java +++ b/source/java/org/alfresco/repo/model/filefolder/GetChildrenCannedQueryFactory.java @@ -44,6 +44,6 @@ public class GetChildrenCannedQueryFactory extends org.alfresco.repo.node.getchi { NodePropertyHelper nodePropertyHelper = new NodePropertyHelper(dictionaryService, qnameDAO, localeDAO, contentDataDAO); - return (CannedQuery) new GetChildrenCannedQuery(nodeDAO, qnameDAO, cannedQueryDAO, nodePropertyHelper, tenantService, methodSecurity, parameters, hiddenAspect); + return (CannedQuery) new GetChildrenCannedQuery(nodeDAO, qnameDAO, cannedQueryDAO, nodePropertyHelper, tenantService, methodSecurity, parameters, hiddenAspect, dictionaryService); } } diff --git a/source/java/org/alfresco/repo/node/getchildren/GetChildrenCannedQuery.java b/source/java/org/alfresco/repo/node/getchildren/GetChildrenCannedQuery.java index 3ea7ab1930..295042123a 100644 --- a/source/java/org/alfresco/repo/node/getchildren/GetChildrenCannedQuery.java +++ b/source/java/org/alfresco/repo/node/getchildren/GetChildrenCannedQuery.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2011 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -85,6 +85,7 @@ public class GetChildrenCannedQuery extends AbstractCannedQueryPermissions filterSortProps, FilterSortNodeEntity params) { int cnt = 0; + int propCnt = 0; for (QName filterSortProp : filterSortProps) { @@ -292,7 +294,7 @@ public class GetChildrenCannedQuery extends AbstractCannedQueryPermissions permHits = new HashSet(100); private Set permMisses = new HashSet(100); - private NodeRef testFolder; - @SuppressWarnings({ "rawtypes" }) private NamedObjectRegistry cannedQueryRegistry; + private static final String CQ_FACTORY_NAME = "fileFolderGetChildrenCannedQueryFactory"; @SuppressWarnings({ "unchecked", "rawtypes" }) @Override @@ -131,12 +141,13 @@ public class GetChildrenCannedQueryTest extends TestCase nodeService = (NodeService)ctx.getBean("NodeService"); contentService = (ContentService)ctx.getBean("ContentService"); mimetypeService = (MimetypeService)ctx.getBean("MimetypeService"); + dictionaryService = (DictionaryService)ctx.getBean("DictionaryService"); personService = (PersonService)ctx.getBean("PersonService"); authenticationService = (MutableAuthenticationService)ctx.getBean("AuthenticationService"); permissionService = (PermissionService)ctx.getBean("PermissionService"); ratingService = (RatingService)ctx.getBean("RatingService"); - + dictionaryDAO = (DictionaryDAO) ctx.getBean("dictionaryDAO"); tenantService = (TenantService) ctx.getBean("tenantService"); @@ -145,7 +156,7 @@ public class GetChildrenCannedQueryTest extends TestCase GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = new GetChildrenCannedQueryFactory(); - getChildrenCannedQueryFactory.setBeanName("getChildrenCannedQueryFactory"); + getChildrenCannedQueryFactory.setBeanName("fileFolderGetChildrenCannedQueryFactory"); getChildrenCannedQueryFactory.setRegistry(cannedQueryRegistry); getChildrenCannedQueryFactory.setCannedQueryDAO((CannedQueryDAO)ctx.getBean("cannedQueryDAO")); @@ -155,16 +166,17 @@ public class GetChildrenCannedQueryTest extends TestCase getChildrenCannedQueryFactory.setLocaleDAO((LocaleDAO)ctx.getBean("localeDAO")); getChildrenCannedQueryFactory.setNodeDAO((NodeDAO)ctx.getBean("nodeDAO")); getChildrenCannedQueryFactory.setQnameDAO((QNameDAO)ctx.getBean("qnameDAO")); + getChildrenCannedQueryFactory.setHiddenAspect((HiddenAspect)ctx.getBean("hiddenAspect")); getChildrenCannedQueryFactory.setMethodSecurity((MethodSecurityBean)ctx.getBean("FileFolderService_security_list")); getChildrenCannedQueryFactory.afterPropertiesSet(); - + fiveStarRatingScheme = ratingService.getRatingScheme("fiveStarRatingScheme"); assertNotNull(fiveStarRatingScheme); likesRatingScheme = ratingService.getRatingScheme("likesRatingScheme"); assertNotNull(likesRatingScheme); - + if (! setupTestData) { AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); @@ -179,7 +191,7 @@ public class GetChildrenCannedQueryTest extends TestCase bootstrap.setDictionaryDAO(dictionaryDAO); bootstrap.setTenantService(tenantService); bootstrap.bootstrap(); - + createUser(TEST_USER_PREFIX, TEST_USER, TEST_USER); createUser(TEST_USER_PREFIX+"aaaa", TEST_USER_PREFIX+"bbbb", TEST_USER_PREFIX+"cccc"); @@ -187,13 +199,16 @@ public class GetChildrenCannedQueryTest extends TestCase createUser(TEST_USER_PREFIX+"dddd", TEST_USER_PREFIX+"ffff", TEST_USER_PREFIX+"gggg"); createUser(TEST_USER_PREFIX+"hhhh", TEST_USER_PREFIX+"cccc", TEST_USER_PREFIX+"jjjj"); - NodeRef testParentFolder = repositoryHelper.getCompanyHome(); + NodeRef testParentFolder = getOrCreateParentTestFolder("GetChildrenCannedQueryTest-"+TEST_RUN_ID); - // create folder subtype - createFolder(testParentFolder, "emptySystemFolder", ContentModel.TYPE_SYSTEM_FOLDER); + // create folder subtype (note: system folder here) + createFolder(testParentFolder, FOLDER_3, TEST_FOLDER_SUBTYPE); // create content subtype (note: no pun intended ... "cm:savedquery" already exists in content model ... but is NOT related to canned queries !) - createContent(testParentFolder, "textContent", QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "savedquery")); + createContent(testParentFolder, "textContent", TEST_CONTENT_SUBTYPE); + + createFolder(testParentFolder, FOLDER_5, ContentModel.TYPE_FOLDER); + createFolder(testParentFolder, FOLDER_4, ContentModel.TYPE_FOLDER); boolean canRead = true; @@ -210,8 +225,11 @@ public class GetChildrenCannedQueryTest extends TestCase loadContent(testParentFolder, "quick.gif", "YY title "+TEST_RUN, "BB description", canRead, permMisses); loadContent(testParentFolder, "quick.xml", "ZZ title" +TEST_RUN, "BB description", canRead, permMisses); + createFolder(testParentFolder, FOLDER_2, ContentModel.TYPE_FOLDER); + createFolder(testParentFolder, FOLDER_1, ContentModel.TYPE_FOLDER); + setupTestData = true; - + // double-check permissions - see testPermissions AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER); @@ -241,18 +259,29 @@ public class GetChildrenCannedQueryTest extends TestCase assertTrue(permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.ALLOWED); } } - + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); - testFolder = createFolder(repositoryHelper.getCompanyHome(), "testFolder1", QName.createQName("http://www.alfresco.org/test/getchildrentest/1.0", "folder")); + + NodeRef testFolder = createFolder(repositoryHelper.getCompanyHome(), "GetChildrenCannedQueryTest-testFolder-"+TEST_RUN_ID, QName.createQName("http://www.alfresco.org/test/getchildrentest/1.0", "folder")); createContent(testFolder, "textContent1", ContentModel.TYPE_CONTENT); createContent(testFolder, QName.createQName("http://www.alfresco.org/test/getchildrentest/1.0", "contains1"), "textContent2", ContentModel.TYPE_CONTENT); - + AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER); } + private NodeRef getOrCreateParentTestFolder(String name) throws Exception + { + NodeRef testFolder = nodeService.getChildByName(repositoryHelper.getCompanyHome(), ContentModel.ASSOC_CONTAINS, name); + if (testFolder == null) + { + testFolder = createFolder(repositoryHelper.getCompanyHome(), name, ContentModel.TYPE_FOLDER); + } + return testFolder; + } + public void testSetup() throws Exception { - NodeRef parentNodeRef = repositoryHelper.getCompanyHome(); + NodeRef parentNodeRef = getOrCreateParentTestFolder("GetChildrenCannedQueryTest-"+TEST_RUN_ID); PagingResults results = list(parentNodeRef, -1, -1, 0); assertTrue(results.getPage().size() > 3); @@ -260,7 +289,7 @@ public class GetChildrenCannedQueryTest extends TestCase public void testMaxItems() throws Exception { - NodeRef parentNodeRef = repositoryHelper.getCompanyHome(); + NodeRef parentNodeRef = getOrCreateParentTestFolder("GetChildrenCannedQueryTest-"+TEST_RUN_ID); PagingResults results = list(parentNodeRef, -1, -1, 0); assertFalse(results.hasMoreItems()); @@ -285,7 +314,7 @@ public class GetChildrenCannedQueryTest extends TestCase public void testPaging() throws Exception { - NodeRef parentNodeRef = repositoryHelper.getCompanyHome(); + NodeRef parentNodeRef = getOrCreateParentTestFolder("GetChildrenCannedQueryTest-"+TEST_RUN_ID); PagingResults results = list(parentNodeRef, -1, -1, 0); assertFalse(results.hasMoreItems()); @@ -339,7 +368,7 @@ public class GetChildrenCannedQueryTest extends TestCase public void testTypeFiltering() throws Exception { - NodeRef parentNodeRef = repositoryHelper.getCompanyHome(); + NodeRef parentNodeRef = getOrCreateParentTestFolder("GetChildrenCannedQueryTest-"+TEST_RUN_ID); // note: parent should contain test example(s) of each type @@ -395,7 +424,7 @@ public class GetChildrenCannedQueryTest extends TestCase public void testPropertyStringFiltering() throws Exception { - NodeRef parentNodeRef = repositoryHelper.getCompanyHome(); + NodeRef parentNodeRef = getOrCreateParentTestFolder("GetChildrenCannedQueryTest-"+TEST_RUN_ID); filterByPropAndCheck(parentNodeRef, ContentModel.PROP_NAME, "GC-CQ-File-"+TEST_RUN+"-", FilterTypeString.STARTSWITH, 5); filterByPropAndCheck(parentNodeRef, ContentModel.PROP_NAME, "gc-CQ-File-"+TEST_RUN+"-", FilterTypeString.STARTSWITH, 0); @@ -477,7 +506,8 @@ public class GetChildrenCannedQueryTest extends TestCase public void testPropertySorting() throws Exception { - NodeRef parentNodeRef = repositoryHelper.getCompanyHome(); + NodeRef parentNodeRef = getOrCreateParentTestFolder("GetChildrenCannedQueryTest-"+TEST_RUN_ID); + NodeRef nodeRef1 = null; NodeRef nodeRef2 = null; NodeRef nodeRef3 = null; @@ -494,17 +524,17 @@ public class GetChildrenCannedQueryTest extends TestCase AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); try { - nodeRef1 = createContent(parentNodeRef, "rating1", ContentModel.TYPE_CONTENT); - nodeRef2 = createContent(parentNodeRef, "rating2", ContentModel.TYPE_CONTENT); - nodeRef3 = createContent(parentNodeRef, "rating3", ContentModel.TYPE_CONTENT); - nodeRef4 = createContent(parentNodeRef, "rating4", ContentModel.TYPE_CONTENT); - nodeRef5 = createContent(parentNodeRef, "rating5", ContentModel.TYPE_CONTENT); - - nodeRef6 = createContent(parentNodeRef, "rating6", ContentModel.TYPE_CONTENT); - nodeRef7 = createContent(parentNodeRef, "rating7", ContentModel.TYPE_CONTENT); - nodeRef8 = createContent(parentNodeRef, "rating8", ContentModel.TYPE_CONTENT); - nodeRef9 = createContent(parentNodeRef, "rating9", ContentModel.TYPE_CONTENT); - nodeRef10 = createContent(parentNodeRef, "rating10", ContentModel.TYPE_CONTENT); + nodeRef1 = createContent(parentNodeRef, "rating1", ContentModel.TYPE_CONTENT); + nodeRef2 = createContent(parentNodeRef, "rating2", ContentModel.TYPE_CONTENT); + nodeRef3 = createContent(parentNodeRef, "rating3", ContentModel.TYPE_CONTENT); + nodeRef4 = createContent(parentNodeRef, "rating4", ContentModel.TYPE_CONTENT); + nodeRef5 = createContent(parentNodeRef, "rating5", ContentModel.TYPE_CONTENT); + + nodeRef6 = createContent(parentNodeRef, "rating6", ContentModel.TYPE_CONTENT); + nodeRef7 = createContent(parentNodeRef, "rating7", ContentModel.TYPE_CONTENT); + nodeRef8 = createContent(parentNodeRef, "rating8", ContentModel.TYPE_CONTENT); + nodeRef9 = createContent(parentNodeRef, "rating9", ContentModel.TYPE_CONTENT); + nodeRef10 = createContent(parentNodeRef, "rating10", ContentModel.TYPE_CONTENT); } finally { @@ -523,7 +553,7 @@ public class GetChildrenCannedQueryTest extends TestCase ratingService.applyRating(nodeRef8, 1.0f, "likesRatingScheme"); ratingService.applyRating(nodeRef9, 1.0f, "likesRatingScheme"); ratingService.applyRating(nodeRef10, 1.0f, "likesRatingScheme"); - + // do children canned query PagingResults results = list(parentNodeRef, -1, -1, 0); @@ -538,10 +568,13 @@ public class GetChildrenCannedQueryTest extends TestCase sortQNames.add(ContentModel.PROP_CREATOR); sortQNames.add(ContentModel.PROP_MODIFIED); sortQNames.add(ContentModel.PROP_MODIFIER); + + // special (pseudo) content/node props sortQNames.add(GetChildrenCannedQuery.SORT_QNAME_CONTENT_SIZE); sortQNames.add(GetChildrenCannedQuery.SORT_QNAME_CONTENT_MIMETYPE); sortQNames.add(GetChildrenCannedQuery.SORT_QNAME_NODE_TYPE); - + sortQNames.add(GetChildrenCannedQuery.SORT_QNAME_NODE_IS_FOLDER); + // Add in the ratings properties on which to sort sortQNames.add(QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "fiveStarRatingSchemeCount")); sortQNames.add(QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "likesRatingSchemeCount")); @@ -553,7 +586,7 @@ public class GetChildrenCannedQueryTest extends TestCase sortAndCheck(parentNodeRef, sortQName, true); // ascending } - // sort with two props + // sort with two props - title first, then description List> sortPairs = new ArrayList>(3); sortPairs.add(new Pair(ContentModel.PROP_TITLE, false)); sortPairs.add(new Pair(ContentModel.PROP_DESCRIPTION, false)); @@ -562,12 +595,40 @@ public class GetChildrenCannedQueryTest extends TestCase assertEquals(TEST_FILE_PREFIX+"quick.pdf", nodeService.getProperty(results.getPage().get(0), ContentModel.PROP_NAME)); // ZZ title + YY description assertEquals(TEST_FILE_PREFIX+"quick.txt", nodeService.getProperty(results.getPage().get(1), ContentModel.PROP_NAME)); // ZZ title + XX description + // sort with two props - folders first (ALF-13968) then by name + sortPairs = new ArrayList>(3); + sortPairs.add(new Pair(GetChildrenCannedQuery.SORT_QNAME_NODE_IS_FOLDER, false)); + sortPairs.add(new Pair(ContentModel.PROP_NAME, true)); + + results = list(parentNodeRef, -1, -1, 0, null, null, sortPairs); + + assertEquals(FOLDER_1, nodeService.getProperty(results.getPage().get(0), ContentModel.PROP_NAME)); + assertEquals(FOLDER_2, nodeService.getProperty(results.getPage().get(1), ContentModel.PROP_NAME)); + assertEquals(FOLDER_3, nodeService.getProperty(results.getPage().get(2), ContentModel.PROP_NAME)); + assertEquals(FOLDER_4, nodeService.getProperty(results.getPage().get(3), ContentModel.PROP_NAME)); + assertEquals(FOLDER_5, nodeService.getProperty(results.getPage().get(4), ContentModel.PROP_NAME)); + + assertEquals(TEST_FILE_PREFIX+"quick.bmp", nodeService.getProperty(results.getPage().get(5), ContentModel.PROP_NAME)); + assertEquals(TEST_FILE_PREFIX+"quick.doc", nodeService.getProperty(results.getPage().get(6), ContentModel.PROP_NAME)); sortPairs = new ArrayList>(3); - sortPairs.add(new Pair(ContentModel.PROP_NAME, true)); - sortPairs.add(new Pair(ContentModel.PROP_TITLE, true)); - sortPairs.add(new Pair(ContentModel.PROP_DESCRIPTION, true)); - sortPairs.add(new Pair(ContentModel.PROP_MODIFIED, true)); + sortPairs.add(new Pair(GetChildrenCannedQuery.SORT_QNAME_NODE_IS_FOLDER, true)); + sortPairs.add(new Pair(ContentModel.PROP_NAME, false)); + + results = list(parentNodeRef, -1, -1, 0, null, null, sortPairs); + + // note: this test assumes that children fit on one page + int len = results.getPage().size(); + + assertEquals("textContent", nodeService.getProperty(results.getPage().get(0), ContentModel.PROP_NAME)); + assertEquals("rating9", nodeService.getProperty(results.getPage().get(1), ContentModel.PROP_NAME)); + + assertEquals(FOLDER_5, nodeService.getProperty(results.getPage().get(len-5), ContentModel.PROP_NAME)); + assertEquals(FOLDER_4, nodeService.getProperty(results.getPage().get(len-4), ContentModel.PROP_NAME)); + assertEquals(FOLDER_3, nodeService.getProperty(results.getPage().get(len-3), ContentModel.PROP_NAME)); + assertEquals(FOLDER_2, nodeService.getProperty(results.getPage().get(len-2), ContentModel.PROP_NAME)); + assertEquals(FOLDER_1, nodeService.getProperty(results.getPage().get(len-1), ContentModel.PROP_NAME)); + // TODO - sort with three props @@ -575,6 +636,12 @@ public class GetChildrenCannedQueryTest extends TestCase try { // -ve test + sortPairs = new ArrayList>(3); + sortPairs.add(new Pair(ContentModel.PROP_NAME, true)); + sortPairs.add(new Pair(ContentModel.PROP_TITLE, true)); + sortPairs.add(new Pair(ContentModel.PROP_DESCRIPTION, true)); + sortPairs.add(new Pair(ContentModel.PROP_MODIFIED, true)); + results = list(parentNodeRef, -1, -1, 0, null, null, sortPairs); fail("Unexpected - cannot sort with more than three props"); } @@ -588,7 +655,7 @@ public class GetChildrenCannedQueryTest extends TestCase { AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER); - NodeRef parentNodeRef = repositoryHelper.getCompanyHome(); + NodeRef parentNodeRef = getOrCreateParentTestFolder("GetChildrenCannedQueryTest-"+TEST_RUN_ID); PagingResults results = list(parentNodeRef, -1, -1, 0); assertFalse(results.hasMoreItems()); @@ -627,7 +694,7 @@ public class GetChildrenCannedQueryTest extends TestCase { AuthenticationUtil.pushAuthentication(); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); - + NodeRef parentNodeRef = nodeService.createNode( repositoryHelper.getCompanyHome(), ContentModel.ASSOC_CONTAINS, @@ -714,8 +781,10 @@ public class GetChildrenCannedQueryTest extends TestCase assertEquals("", 0, totalCnt); } - public void testRestrictByAssocType() + public void testRestrictByAssocType() throws Exception { + NodeRef parentNodeRef = getOrCreateParentTestFolder("GetChildrenCannedQueryTest-testFolder-"+TEST_RUN_ID); + Set assocTypeQNames = new HashSet(3); Set childTypeQNames = new HashSet(3); @@ -723,14 +792,14 @@ public class GetChildrenCannedQueryTest extends TestCase assocTypeQNames.add(ContentModel.ASSOC_CONTAINS); childTypeQNames.clear(); childTypeQNames.add(ContentModel.TYPE_CONTENT); - List children = filterByAssocTypeAndCheck(testFolder, assocTypeQNames, childTypeQNames); + List children = filterByAssocTypeAndCheck(parentNodeRef, assocTypeQNames, childTypeQNames); assertEquals(1, children.size()); assocTypeQNames.clear(); assocTypeQNames.add(QName.createQName("http://www.alfresco.org/test/getchildrentest/1.0", "contains1")); childTypeQNames.clear(); childTypeQNames.add(ContentModel.TYPE_CONTENT); - children = filterByAssocTypeAndCheck(testFolder, assocTypeQNames, childTypeQNames); + children = filterByAssocTypeAndCheck(parentNodeRef, assocTypeQNames, childTypeQNames); assertEquals(1, children.size()); assocTypeQNames.clear(); @@ -738,7 +807,7 @@ public class GetChildrenCannedQueryTest extends TestCase assocTypeQNames.add(ContentModel.ASSOC_CONTAINS); childTypeQNames.clear(); childTypeQNames.add(ContentModel.TYPE_CONTENT); - children = filterByAssocTypeAndCheck(testFolder, assocTypeQNames, childTypeQNames); + children = filterByAssocTypeAndCheck(parentNodeRef, assocTypeQNames, childTypeQNames); assertEquals(2, children.size()); } @@ -749,7 +818,7 @@ public class GetChildrenCannedQueryTest extends TestCase pagingRequest.setRequestTotalCountMax(requestTotalCountMax); // get canned query - GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory)cannedQueryRegistry.getNamedObject("getChildrenCannedQueryFactory"); + GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory)cannedQueryRegistry.getNamedObject(CQ_FACTORY_NAME); GetChildrenCannedQuery cq = (GetChildrenCannedQuery)getChildrenCannedQueryFactory.getCannedQuery(parentNodeRef, pattern, null, null, null, sortProps, pagingRequest); // execute canned query @@ -925,6 +994,10 @@ public class GetChildrenCannedQueryTest extends TestCase { val = nodeService.getType(nodeRef); } + else if (sortPropQName.equals(GetChildrenCannedQuery.SORT_QNAME_NODE_IS_FOLDER)) + { + val = dictionaryService.isSubClass(nodeService.getType(nodeRef), ContentModel.TYPE_FOLDER); + } else { val = nodeService.getProperty(nodeRef, sortPropQName); @@ -972,27 +1045,34 @@ public class GetChildrenCannedQueryTest extends TestCase { result = ((QName)val).compareTo((QName)prevVal); } + else if (val instanceof Boolean) + { + result = ((Boolean)val).compareTo((Boolean)prevVal); + } else { fail("Unsupported sort type ("+nodeRef+"): "+val.getClass().getName()); } + String prevName = (String)nodeService.getProperty(prevNodeRef, ContentModel.PROP_NAME); + String currName = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); + if (! sortAscending) { assertTrue( - "Not descending: \n" + + "Not descending: "+result+"\n" + " Iteration: " + currentIteration + " out of " + count + "\n" + - " Previous: " + prevNodeRef + " had " + prevVal + "\n" + - " Current : " + nodeRef + " had " + val, + " Previous: " + prevNodeRef + " had " + prevVal + " ("+prevName+")\n" + + " Current : " + nodeRef + " had " + val + " ("+currName+")", result <= 0); } else { assertTrue( - "Not ascending: \n" + + "Not ascending: "+result+"\n" + " Iteration: " + currentIteration + " out of " + count + "\n" + - " Previous: " + prevNodeRef + " had " + prevVal + "\n" + - " Current : " + nodeRef + " had " + val, + " Previous: " + prevNodeRef + " had " + prevVal + " ("+prevName+")\n" + + " Current : " + nodeRef + " had " + val + " ("+currName+")", result >= 0); } } @@ -1015,8 +1095,8 @@ public class GetChildrenCannedQueryTest extends TestCase PagingRequest pagingRequest = new PagingRequest(skipCount, maxItems, null); pagingRequest.setRequestTotalCountMax(requestTotalCountMax); - // get canned query - GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory)cannedQueryRegistry.getNamedObject("getChildrenCannedQueryFactory"); + // get canned query (note: test the fileFolder extension - including support for sorting folders first) + GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory)cannedQueryRegistry.getNamedObject(CQ_FACTORY_NAME); GetChildrenCannedQuery cq = (GetChildrenCannedQuery)getChildrenCannedQueryFactory.getCannedQuery(parentNodeRef, null, null, childTypeQNames, filterProps, sortProps, pagingRequest); // execute canned query @@ -1040,7 +1120,7 @@ public class GetChildrenCannedQueryTest extends TestCase pagingRequest.setRequestTotalCountMax(requestTotalCountMax); // get canned query - GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory)cannedQueryRegistry.getNamedObject("getChildrenCannedQueryFactory"); + GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory)cannedQueryRegistry.getNamedObject(CQ_FACTORY_NAME); GetChildrenCannedQuery cq = (GetChildrenCannedQuery)getChildrenCannedQueryFactory.getCannedQuery(parentNodeRef, null, assocTypeQNames, childTypeQNames, filterProps, sortProps, pagingRequest); // execute canned query diff --git a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java index e554bfcfcd..e31c09b0d0 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -1205,8 +1205,8 @@ public class RuleServiceImpl if (subAction.getActionDefinitionName().equals(MailActionExecuter.NAME)) { subAction.setParameterValue(MailActionExecuter.PARAM_SEND_AFTER_COMMIT, true); - } - } + } + } } else if (action.getActionDefinitionName().equals(MailActionExecuter.NAME)) { diff --git a/source/java/org/alfresco/repo/rule/RuleTypeImpl.java b/source/java/org/alfresco/repo/rule/RuleTypeImpl.java index b8703aae04..59a812006e 100644 --- a/source/java/org/alfresco/repo/rule/RuleTypeImpl.java +++ b/source/java/org/alfresco/repo/rule/RuleTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -127,22 +127,34 @@ public class RuleTypeImpl extends CommonResourceAbstractBase implements RuleType true, this.name); + String ruleContext = null; + if (logger.isDebugEnabled() == true) + { + if (actionedUponNodeRef != null) + { + ruleContext = (executeRuleImmediately ? " now" : " ") + " on " + nodeService.getPath(actionedUponNodeRef).toString().replaceAll("\\{[^}]*}", ""); + } + } + if (rules.size() != 0) { for (Rule rule : rules) - { + { if (logger.isDebugEnabled() == true) { - NodeRef ruleNodeRef = rule.getNodeRef(); if (nodeRef != null) { - logger.debug("Triggering rule " + ruleNodeRef.toString()); + ruleContext = " " + rule.getTitle() + ruleContext; } } // Only queue if the rule is not disabled - if (rule.getRuleDisabled() == false) + if (rule.getRuleDisabled() == false && ruleService.rulesEnabled(ruleService.getOwningNodeRef(rule))) { + if (logger.isDebugEnabled() == true) + { + logger.debug("Triggering rule" + ruleContext); + } if (executeRuleImmediately == false) { // Queue the rule to be executed at the end of the transaction (but still in the transaction) @@ -154,13 +166,17 @@ public class RuleTypeImpl extends CommonResourceAbstractBase implements RuleType ((RuntimeRuleService)ruleService).executeRule(rule, actionedUponNodeRef, null); } } + else if (logger.isDebugEnabled() == true) + { + logger.debug("Disabled rule" + ruleContext); + } } } else { if (logger.isDebugEnabled() == true) { - logger.debug("This node has no rules to trigger."); + logger.debug("No rules to trigger" + ruleContext); } } } diff --git a/source/java/org/alfresco/repo/rule/RulesAspect.java b/source/java/org/alfresco/repo/rule/RulesAspect.java index 838f8e0391..d8265ffa9f 100644 --- a/source/java/org/alfresco/repo/rule/RulesAspect.java +++ b/source/java/org/alfresco/repo/rule/RulesAspect.java @@ -18,6 +18,7 @@ */ package org.alfresco.repo.rule; +import java.util.List; import java.util.Map; import org.alfresco.model.ContentModel; @@ -47,7 +48,8 @@ public class RulesAspect implements CopyServicePolicies.OnCopyNodePolicy, CopyServicePolicies.OnCopyCompletePolicy, NodeServicePolicies.OnAddAspectPolicy, - NodeServicePolicies.BeforeDeleteChildAssociationPolicy + NodeServicePolicies.BeforeRemoveAspectPolicy, + NodeServicePolicies.BeforeDeleteNodePolicy { private PolicyComponent policyComponent; private BehaviourFilter behaviourFilter; @@ -95,11 +97,14 @@ public class RulesAspect implements NodeServicePolicies.OnAddAspectPolicy.QNAME, RuleModel.ASPECT_RULES, new JavaBehaviour(this, "onAddAspect")); - this.policyComponent.bindAssociationBehaviour( - NodeServicePolicies.BeforeDeleteChildAssociationPolicy.QNAME, + this.policyComponent.bindClassBehaviour( + NodeServicePolicies.BeforeRemoveAspectPolicy.QNAME, RuleModel.ASPECT_RULES, - RuleModel.ASSOC_RULE_FOLDER, - new JavaBehaviour(this, "beforeDeleteChildAssociation")); + new JavaBehaviour(this, "beforeRemoveAspect")); + this.policyComponent.bindClassBehaviour( + NodeServicePolicies.BeforeDeleteNodePolicy.QNAME, + RuleModel.ASPECT_RULES, + new JavaBehaviour(this, "beforeDeleteNode")); } /** @@ -130,26 +135,65 @@ public class RulesAspect implements } } + /** - * ALF-11923 - * @since 4.1.1 - * @author Derek Hulley + * The rule folder & below will be deleted automatically in the normal way, so we don't need to worry about them. + * But we need additional handling for any other folders which have rules linked to this folder's rules. See + * ALF-11923, ALF-15262. + * + * @see org.alfresco.repo.node.NodeServicePolicies.BeforeRemoveAspectPolicy#beforeRemoveAspect(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName) */ @Override - public void beforeDeleteChildAssociation(ChildAssociationRef childAssocRef) + public void beforeRemoveAspect(NodeRef nodeRef, QName aspectTypeQName) { - NodeRef nodeRef = childAssocRef.getParentRef(); + if (!aspectTypeQName.equals(RuleModel.ASPECT_RULES)) + { + return; + } + this.ruleService.disableRules(nodeRef); try { - // Just remove the aspect for the association - nodeService.removeAspect(nodeRef, RuleModel.ASPECT_RULES); + for (ChildAssociationRef childAssocRef : nodeService.getChildAssocs(nodeRef, RuleModel.ASSOC_RULE_FOLDER, + RuleModel.ASSOC_RULE_FOLDER, false)) + { + // We are only interested in the deletion of primary associations to a rule folder, which usually + // happens when all rules in a folder are deleted and the ASPECT_RULES aspect is removed + if (!childAssocRef.isPrimary()) + { + continue; + } + NodeRef savedRuleFolderRef = childAssocRef.getChildRef(); + // Cascade the removal to all secondary (linked) parents + List linkedAssocs = nodeService.getParentAssocs(savedRuleFolderRef); + for (ChildAssociationRef linkAssoc : linkedAssocs) + { + if (!linkAssoc.isPrimary()) + { + // Remove the aspect from linked parents; this will also delete the linking secondary + // association + nodeService.removeAspect(linkAssoc.getParentRef(), RuleModel.ASPECT_RULES); + } + } + } } finally { - ruleService.enableRules(nodeRef); + this.ruleService.enableRules(nodeRef); } } + + /** + * @since 3.4.11 + * @author Neil McErlean + */ + @Override + public void beforeDeleteNode(NodeRef nodeRef) + { + // In case the event isn't triggered automatically by node service (e.g. on a cascaded node tree deletion), + // trigger handling removal of the rules aspect. + beforeRemoveAspect(nodeRef, RuleModel.ASPECT_RULES); + } /** * @return Returns {@link RulesAspectCopyBehaviourCallback} diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java b/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java index 89a3e2ce3e..371a393a38 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java @@ -23,13 +23,11 @@ import java.util.Set; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.ContentServicePolicies; -import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.transaction.TransactionalResourceHelper; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -38,7 +36,7 @@ import org.apache.commons.logging.LogFactory; * @author Roy Wetherall */ public class OnContentUpdateRuleTrigger extends RuleTriggerAbstractBase - implements ContentServicePolicies.OnContentUpdatePolicy + implements ContentServicePolicies.OnContentPropertyUpdatePolicy { /** * The logger @@ -78,53 +76,65 @@ public class OnContentUpdateRuleTrigger extends RuleTriggerAbstractBase { // Bind behaviour this.policyComponent.bindClassBehaviour( - ContentServicePolicies.OnContentUpdatePolicy.QNAME, + ContentServicePolicies.OnContentPropertyUpdatePolicy.QNAME, this, - new JavaBehaviour(this, "onContentUpdate")); + new JavaBehaviour(this, "onContentPropertyUpdate")); } + + /** - * @see org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy#onContentUpdate(org.alfresco.service.cmr.repository.NodeRef, boolean) + * @see org.alfresco.repo.content.ContentServicePolicies.OnContentPropertyUpdatePolicy#onContentPropertyUpdate(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.cmr.repository.ContentData, org.alfresco.service.cmr.repository.ContentData) */ - public void onContentUpdate(NodeRef nodeRef, boolean newContent) + @Override + public void onContentPropertyUpdate(NodeRef nodeRef, QName propertyQName, ContentData beforeValue, + ContentData afterValue) { // Break out early if rules are not enabled if (!areRulesEnabled()) { return; } - - // Check the new content and make sure that we do indeed want to trigger the rule - boolean fail = false; - if (newContent == true) + + // Check the new content and make sure that we do indeed want to trigger the rule + if (propertyQName.equals(ContentModel.PROP_PREFERENCE_VALUES)) { - fail = nodeService.hasAspect(nodeRef, ContentModel.ASPECT_NO_CONTENT); - - if (fail == false) - { - // Note: Don't use the ContentService.getReader() because we don't need access to the content - ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); - if (contentData == null) - { - fail = true; - } - } + return; } - - // Double check for content created in this transaction - if (fail == false && !newContent) + + // Check for new content + boolean newContent = beforeValue == null && afterValue != null; + + // Check the new content and make sure that we do indeed want to trigger the rule + if (newContent) + { + if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_NO_CONTENT)) + { + return; + } + + // Note: Don't use the ContentService.getReader() because we don't need access to the content + if (!ContentData.hasContent(afterValue)) + { + return; + } + } + // An update, but double check for content created in this transaction + else { Set newNodeRefSet = TransactionalResourceHelper.getSet(RULE_TRIGGER_NEW_NODES); - boolean wasCreatedInTxn = newNodeRefSet.contains(nodeRef); - if (logger.isDebugEnabled() && wasCreatedInTxn) + if (newNodeRefSet.contains(nodeRef)) { - logger.debug("Receiving content property update for node created in transaction: " + nodeRef); + if (logger.isDebugEnabled()) + { + logger.debug("Receiving content property update for node created in transaction: " + nodeRef); + } + return; } - fail = wasCreatedInTxn; } // Trigger the rules in the appropriate way - if (fail == false && newContent == this.onNewContent) + if (newContent == this.onNewContent) { if (triggerParentRules == true) { diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/OnMoveNodeRuleTrigger.java b/source/java/org/alfresco/repo/rule/ruletrigger/OnMoveNodeRuleTrigger.java index 3d0db954de..197d70bff1 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/OnMoveNodeRuleTrigger.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/OnMoveNodeRuleTrigger.java @@ -1,8 +1,27 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ package org.alfresco.repo.rule.ruletrigger; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; @@ -47,21 +66,32 @@ public class OnMoveNodeRuleTrigger extends RuleTriggerAbstractBase implements No // Check that it is not rename operation. if (!oldChildAssocRef.getParentRef().equals(newChildAssocRef.getParentRef())) { - triggerChildrenRules(newChildAssocRef, newChildAssocRef); + triggerChildrenRules(newChildAssocRef); } } - private void triggerChildrenRules(ChildAssociationRef oldChildAssocRef, ChildAssociationRef newChildAssocRef) + private void triggerChildrenRules(ChildAssociationRef newChildAssocRef) { - // Break out early if rules are not enabled - if (!areRulesEnabled()) + NodeRef nodeRef = newChildAssocRef.getChildRef(); + boolean enabled = ruleService.rulesEnabled(nodeRef); + try { - return; + if (enabled) + { + ruleService.disableRules(nodeRef); + } + triggerRules(newChildAssocRef.getParentRef(), nodeRef); + for (ChildAssociationRef ref : nodeService.getChildAssocs(nodeRef)) + { + triggerChildrenRules(ref); + } } - triggerRules(newChildAssocRef.getParentRef(), newChildAssocRef.getChildRef()); - for (ChildAssociationRef ref : nodeService.getChildAssocs(newChildAssocRef.getChildRef())) + finally { - triggerChildrenRules(ref, ref); + if (enabled) + { + ruleService.enableRules(nodeRef); + } } } } diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java index cf3a995025..67f1f77346 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -37,194 +37,195 @@ import org.alfresco.util.BaseSpringTest; */ public class RuleTriggerTest extends BaseSpringTest { - private static final String ON_CREATE_NODE_TRIGGER = "on-create-node-trigger"; - private static final String ON_UPDATE_NODE_TRIGGER = "on-update-node-trigger"; - private static final String ON_CREATE_CHILD_ASSOCIATION_TRIGGER = "on-create-child-association-trigger"; - private static final String ON_DELETE_CHILD_ASSOCIATION_TRIGGER = "on-delete-child-association-trigger"; - private static final String ON_CREATE_ASSOCIATION_TRIGGER = "on-create-association-trigger"; - private static final String ON_DELETE_ASSOCIATION_TRIGGER = "on-delete-association-trigger"; - private static final String ON_CONTENT_UPDATE_TRIGGER = "on-content-update-trigger"; + private static final String ON_CREATE_NODE_TRIGGER = "on-create-node-trigger"; + private static final String ON_UPDATE_NODE_TRIGGER = "on-update-node-trigger"; + private static final String ON_MOVE_NODE_TRIGGER = "on-move-node-trigger"; + private static final String ON_CREATE_CHILD_ASSOCIATION_TRIGGER = "on-create-child-association-trigger"; + private static final String ON_DELETE_CHILD_ASSOCIATION_TRIGGER = "on-delete-child-association-trigger"; + private static final String ON_CREATE_ASSOCIATION_TRIGGER = "on-create-association-trigger"; + private static final String ON_DELETE_ASSOCIATION_TRIGGER = "on-delete-association-trigger"; + private static final String ON_CONTENT_UPDATE_TRIGGER = "on-content-update-trigger"; private static final String ON_CONTENT_CREATE_TRIGGER = "on-content-create-trigger"; - private NodeService nodeService; - private ContentService contentService; - - private StoreRef testStoreRef; - private NodeRef rootNodeRef; - - @Override - protected void onSetUpInTransaction() throws Exception - { - ServiceRegistry serviceRegistry = (ServiceRegistry) applicationContext.getBean(ServiceRegistry.SERVICE_REGISTRY); - this.nodeService = serviceRegistry.getNodeService(); - this.contentService = serviceRegistry.getContentService(); + private NodeService nodeService; + private ContentService contentService; + + private StoreRef testStoreRef; + private NodeRef rootNodeRef; + + @Override + protected void onSetUpInTransaction() throws Exception + { + ServiceRegistry serviceRegistry = (ServiceRegistry) applicationContext.getBean(ServiceRegistry.SERVICE_REGISTRY); + this.nodeService = serviceRegistry.getNodeService(); + this.contentService = serviceRegistry.getContentService(); AuthenticationUtil.setRunAsUser(AuthenticationUtil.getSystemUserName()); - - this.testStoreRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis()); + + this.testStoreRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis()); this.rootNodeRef = this.nodeService.getRootNode(this.testStoreRef); - } - - @Override + } + + @Override protected void onTearDownInTransaction() throws Exception { AuthenticationUtil.clearCurrentSecurityContext(); } public void testOnCreateNodeTrigger() - { - TestRuleType ruleType = createTestRuleType(ON_CREATE_NODE_TRIGGER); - assertFalse(ruleType.rulesTriggered); - - // Try and trigger the type + { + TestRuleType ruleType = createTestRuleType(ON_CREATE_NODE_TRIGGER); + assertFalse(ruleType.rulesTriggered); + + // Try and trigger the type this.nodeService.createNode( this.rootNodeRef, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTAINER); - - // Check to see if the rule type has been triggered + + // Check to see if the rule type has been triggered assertTrue(ruleType.rulesTriggered); - } - - public void testOnUpdateNodeTrigger() - { - NodeRef nodeRef = this.nodeService.createNode( + } + + public void testOnUpdateNodeTrigger() + { + NodeRef nodeRef = this.nodeService.createNode( this.rootNodeRef, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTAINER).getChildRef(); - - TestRuleType ruleType = createTestRuleType(ON_UPDATE_NODE_TRIGGER); - assertFalse(ruleType.rulesTriggered); - - // Try and trigger the type - this.nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, "nameChanged"); - - // Check to see if the rule type has been triggered - assertTrue(ruleType.rulesTriggered); - } - -// public void testOnDeleteNodeTrigger() -// { -// NodeRef nodeRef = this.nodeService.createNode( + + TestRuleType ruleType = createTestRuleType(ON_UPDATE_NODE_TRIGGER); + assertFalse(ruleType.rulesTriggered); + + // Try and trigger the type + this.nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, "nameChanged"); + + // Check to see if the rule type has been triggered + assertTrue(ruleType.rulesTriggered); + } + +// public void testOnDeleteNodeTrigger() +// { +// NodeRef nodeRef = this.nodeService.createNode( // this.rootNodeRef, -// ContentModel.ASSOC_CHILDREN, +// ContentModel.ASSOC_CHILDREN, // ContentModel.ASSOC_CHILDREN, // ContentModel.TYPE_CONTAINER).getChildRef(); -// -// TestRuleType ruleType = createTestRuleType(ON_DELETE_NODE_TRIGGER); -// assertFalse(ruleType.rulesTriggered); -// -// // Try and trigger the type -// this.nodeService.deleteNode(nodeRef); -// -// // Check to see if the rule type has been triggered -// assertTrue(ruleType.rulesTriggered); -// } - - public void testOnCreateChildAssociationTrigger() - { - NodeRef nodeRef = this.nodeService.createNode( +// +// TestRuleType ruleType = createTestRuleType(ON_DELETE_NODE_TRIGGER); +// assertFalse(ruleType.rulesTriggered); +// +// // Try and trigger the type +// this.nodeService.deleteNode(nodeRef); +// +// // Check to see if the rule type has been triggered +// assertTrue(ruleType.rulesTriggered); +// } + + public void testOnCreateChildAssociationTrigger() + { + NodeRef nodeRef = this.nodeService.createNode( this.rootNodeRef, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTAINER).getChildRef(); - NodeRef nodeRef2 = this.nodeService.createNode( + NodeRef nodeRef2 = this.nodeService.createNode( this.rootNodeRef, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTAINER).getChildRef(); - - TestRuleType ruleType = createTestRuleType(ON_CREATE_CHILD_ASSOCIATION_TRIGGER); - assertFalse(ruleType.rulesTriggered); - - // Try and trigger the type - this.nodeService.addChild( - nodeRef, - nodeRef2, - ContentModel.ASSOC_CHILDREN, + + TestRuleType ruleType = createTestRuleType(ON_CREATE_CHILD_ASSOCIATION_TRIGGER); + assertFalse(ruleType.rulesTriggered); + + // Try and trigger the type + this.nodeService.addChild( + nodeRef, + nodeRef2, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN); - - // Check to see if the rule type has been triggered - assertTrue(ruleType.rulesTriggered); - } - - public void testOnDeleteChildAssociationTrigger() - { - NodeRef nodeRef = this.nodeService.createNode( + + // Check to see if the rule type has been triggered + assertTrue(ruleType.rulesTriggered); + } + + public void testOnDeleteChildAssociationTrigger() + { + NodeRef nodeRef = this.nodeService.createNode( this.rootNodeRef, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTAINER).getChildRef(); - NodeRef nodeRef2 = this.nodeService.createNode( + NodeRef nodeRef2 = this.nodeService.createNode( this.rootNodeRef, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTAINER).getChildRef(); - this.nodeService.addChild( - nodeRef, - nodeRef2, - ContentModel.ASSOC_CHILDREN, + this.nodeService.addChild( + nodeRef, + nodeRef2, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN); - - TestRuleType ruleType = createTestRuleType(ON_DELETE_CHILD_ASSOCIATION_TRIGGER); - assertFalse(ruleType.rulesTriggered); - - // Try and trigger the type - this.nodeService.removeChild(nodeRef, nodeRef2); - - // Check to see if the rule type has been triggered - assertTrue(ruleType.rulesTriggered); - } - - public void testOnCreateAssociationTrigger() - { - NodeRef nodeRef = this.nodeService.createNode( + + TestRuleType ruleType = createTestRuleType(ON_DELETE_CHILD_ASSOCIATION_TRIGGER); + assertFalse(ruleType.rulesTriggered); + + // Try and trigger the type + this.nodeService.removeChild(nodeRef, nodeRef2); + + // Check to see if the rule type has been triggered + assertTrue(ruleType.rulesTriggered); + } + + public void testOnCreateAssociationTrigger() + { + NodeRef nodeRef = this.nodeService.createNode( this.rootNodeRef, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTAINER).getChildRef(); - NodeRef nodeRef2 = this.nodeService.createNode( + NodeRef nodeRef2 = this.nodeService.createNode( this.rootNodeRef, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTAINER).getChildRef(); - - TestRuleType ruleType = createTestRuleType(ON_CREATE_ASSOCIATION_TRIGGER); - assertFalse(ruleType.rulesTriggered); - - // Try and trigger the type - this.nodeService.createAssociation(nodeRef, nodeRef2, ContentModel.ASSOC_CHILDREN); - - // Check to see if the rule type has been triggered - assertTrue(ruleType.rulesTriggered); - } - - public void testOnDeleteAssociationTrigger() - { - NodeRef nodeRef = this.nodeService.createNode( + + TestRuleType ruleType = createTestRuleType(ON_CREATE_ASSOCIATION_TRIGGER); + assertFalse(ruleType.rulesTriggered); + + // Try and trigger the type + this.nodeService.createAssociation(nodeRef, nodeRef2, ContentModel.ASSOC_CHILDREN); + + // Check to see if the rule type has been triggered + assertTrue(ruleType.rulesTriggered); + } + + public void testOnDeleteAssociationTrigger() + { + NodeRef nodeRef = this.nodeService.createNode( this.rootNodeRef, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTAINER).getChildRef(); - NodeRef nodeRef2 = this.nodeService.createNode( + NodeRef nodeRef2 = this.nodeService.createNode( this.rootNodeRef, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTAINER).getChildRef(); - this.nodeService.createAssociation(nodeRef, nodeRef2, ContentModel.ASSOC_CHILDREN); - - TestRuleType ruleType = createTestRuleType(ON_DELETE_ASSOCIATION_TRIGGER); - assertFalse(ruleType.rulesTriggered); - - // Try and trigger the type - this.nodeService.removeAssociation(nodeRef, nodeRef2, ContentModel.ASSOC_CHILDREN); - - // Check to see if the rule type has been triggered - assertTrue(ruleType.rulesTriggered); - } - + this.nodeService.createAssociation(nodeRef, nodeRef2, ContentModel.ASSOC_CHILDREN); + + TestRuleType ruleType = createTestRuleType(ON_DELETE_ASSOCIATION_TRIGGER); + assertFalse(ruleType.rulesTriggered); + + // Try and trigger the type + this.nodeService.removeAssociation(nodeRef, nodeRef2, ContentModel.ASSOC_CHILDREN); + + // Check to see if the rule type has been triggered + assertTrue(ruleType.rulesTriggered); + } + public void testOnContentCreateTrigger() { NodeRef nodeRef = this.nodeService.createNode( @@ -257,25 +258,25 @@ public class RuleTriggerTest extends BaseSpringTest assertFalse(contentCreate.rulesTriggered); } - public void testOnContentUpdateTrigger() - { - NodeRef nodeRef = this.nodeService.createNode( + public void testOnContentUpdateTrigger() + { + NodeRef nodeRef = this.nodeService.createNode( this.rootNodeRef, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTENT).getChildRef(); - + TestRuleType contentCreate = createTestRuleType(ON_CONTENT_CREATE_TRIGGER); - TestRuleType contentUpdate = createTestRuleType(ON_CONTENT_UPDATE_TRIGGER); + TestRuleType contentUpdate = createTestRuleType(ON_CONTENT_UPDATE_TRIGGER); assertFalse(contentCreate.rulesTriggered); assertFalse(contentUpdate.rulesTriggered); - - // Try and trigger the type - ContentWriter contentWriter = this.contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true); + + // Try and trigger the type + ContentWriter contentWriter = this.contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true); contentWriter.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); contentWriter.setEncoding("UTF-8"); - contentWriter.putContent("some content"); - + contentWriter.putContent("some content"); + // Check to see if the rule type has been triggered assertTrue(contentCreate.rulesTriggered); assertFalse(contentUpdate.rulesTriggered); @@ -311,35 +312,67 @@ public class RuleTriggerTest extends BaseSpringTest assertTrue( "Content update must not fire if the content was created in the same txn.", contentUpdate.rulesTriggered); - } - - private TestRuleType createTestRuleType(String ruleTriggerName) - { - RuleTrigger ruleTrigger = (RuleTrigger)this.applicationContext.getBean(ruleTriggerName); - assertNotNull(ruleTrigger); - TestRuleType ruleType = new TestRuleType(); - ruleTrigger.registerRuleType(ruleType); - return ruleType; - } - - private class TestRuleType implements RuleType - { - public boolean rulesTriggered = false; + } + + public void testOnMoveNodeTrigger() + { + NodeRef nodeRef1 = this.nodeService.createNode(this.rootNodeRef, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, + ContentModel.TYPE_CONTAINER).getChildRef(); - public String getName() - { - return "testRuleType"; - } + NodeRef nodeRef2 = this.nodeService.createNode(this.rootNodeRef, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, + ContentModel.TYPE_CONTAINER).getChildRef(); - public String getDisplayLabel() - { - return "displayLabel"; - } + this.nodeService.createNode(nodeRef2, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, + ContentModel.TYPE_CONTAINER).getChildRef(); - public void triggerRuleType(NodeRef nodeRef, NodeRef actionedUponNodeRef, boolean executeRuleImmediately) - { - // Indicate that the rules have been triggered - this.rulesTriggered = true; - } - } + this.nodeService.createNode(nodeRef2, + ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, + ContentModel.TYPE_CONTAINER).getChildRef(); + + + TestRuleType ruleType = createTestRuleType(ON_MOVE_NODE_TRIGGER); + assertFalse(ruleType.rulesTriggered); + + // Try and trigger the type + this.nodeService.moveNode(nodeRef2, nodeRef1, ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN); + + // Check to see if the rule type has been triggered + assertTrue(ruleType.rulesTriggered); + assertEquals(3, ruleType.triggerCount); + } + + private TestRuleType createTestRuleType(String ruleTriggerName) + { + RuleTrigger ruleTrigger = (RuleTrigger)this.applicationContext.getBean(ruleTriggerName); + assertNotNull(ruleTrigger); + TestRuleType ruleType = new TestRuleType(); + ruleTrigger.registerRuleType(ruleType); + return ruleType; + } + + private class TestRuleType implements RuleType + { + public boolean rulesTriggered = false; + public int triggerCount = 0; + + public String getName() + { + return "testRuleType"; + } + + public String getDisplayLabel() + { + return "displayLabel"; + } + + public void triggerRuleType(NodeRef nodeRef, NodeRef actionedUponNodeRef, boolean executeRuleImmediately) + { + // Indicate that the rules have been triggered + this.rulesTriggered = true; + triggerCount++; + } + } } diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java index 187488fe6c..4308495b4e 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java @@ -371,6 +371,13 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp { return false; } + + // Don't worry about the cascade reindex impact of nodes that aren't containers + if (!mayHaveChildren(childRef)) + { + return false; + } + // Otherwise, if the parent has less children than the child has parents, then cascade // reindex the parent int childCount = nodeService.getChildAssocs(parentRef, RegexQNamePattern.MATCH_ALL, @@ -603,6 +610,59 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp } } + protected boolean deleteLeafOnly(String nodeRef, IndexReader reader, boolean delete) throws LuceneIndexException + { + boolean found = false; + try + { + TermDocs td = reader.termDocs(new Term("LEAFID", nodeRef)); + while (td.next()) + { + found = true; + if (delete) + { + reader.deleteDocument(td.doc()); + } + else + { + break; + } + } + td.close(); + if (found) + { + return true; + } + // For backward compatibility, use old method of locating non-container docs + td = reader.termDocs(new Term("ID", nodeRef)); + while (td.next()) + { + int doc = td.doc(); + Document document = reader.document(doc); + // Exclude all containers except the root (which is also a node!) + Field path = document.getField("PATH"); + if (path == null || path.stringValue().length() == 0) + { + found = true; + if (delete) + { + reader.deleteDocument(doc); + } + else + { + break; + } + } + } + td.close(); + } + catch (IOException e) + { + throw new LuceneIndexException("Failed to delete container and below for " + nodeRef, e); + } + return found; + } + protected Set deleteImpl(String nodeRef, IndexReader deltaReader, IndexReader mainReader) throws LuceneIndexException, IOException { @@ -786,7 +846,9 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp } // Now regenerate the containers for this node if necessary - if (cascade || isCategory(getDictionaryService().getType(nodeService.getType(nodeRef)))) + if (cascade && mayHaveChildren(nodeRef) + && !getCachedChildren(childAssociationsSinceFlush, nodeRef, cascade).isEmpty() + || isCategory(getDictionaryService().getType(nodeService.getType(nodeRef)))) { generateContainersAndBelow(nodeService.getPaths(nodeRef, false), docs, cascade, pathsToRegenerate, childAssociationsSinceFlush); @@ -830,6 +892,7 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp Document xdoc = new Document(); xdoc.add(new Field("ID", stringNodeRef, Field.Store.YES, Field.Index.NO_NORMS, Field.TermVector.NO)); xdoc.add(new Field("TX", nodeStatus.getChangeTxnId(), Field.Store.YES, Field.Index.NO_NORMS, Field.TermVector.NO)); + xdoc.add(new Field("LEAFID", stringNodeRef, Field.Store.YES, Field.Index.NO_NORMS, Field.TermVector.NO)); boolean isAtomic = true; for (QName propertyName : properties.keySet()) { @@ -1049,13 +1112,11 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp break; case REINDEX: // Remove from delta if present - deleteLeafOnly(nodeRef, deltaReader, true); - - // Only mask out the node if it is present in the main index - if (deleteLeafOnly(nodeRef, mainReader, false)); - { + if (!deleteLeafOnly(nodeRef, deltaReader, true)) + { + // Only mask out the node if it is present in the main index deletions.add(nodeRef); - } + } if (!nodeActionMap.containsKey(nodeRef)) { nodeActionMap.put(nodeRef, Action.REINDEX); @@ -1990,13 +2051,14 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp } public int updateFullTextSearch(int size) throws LuceneIndexException - { + { + checkAbleToDoWork(IndexUpdateStatus.ASYNCHRONOUS); + if(getLuceneConfig().isContentIndexingEnabled() == false) { return 0; } - checkAbleToDoWork(IndexUpdateStatus.ASYNCHRONOUS); // if (!mainIndexExists()) // { // remainingCount = size; diff --git a/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerImpl.java index 61139ed7a4..f4d8c4ed8e 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerImpl.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/AbstractLuceneIndexerImpl.java @@ -40,7 +40,6 @@ import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.lucene.document.Document; -import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermDocs; @@ -316,40 +315,6 @@ public abstract class AbstractLuceneIndexerImpl extends AbstractLuceneBase im return found; } - protected boolean deleteLeafOnly(String nodeRef, IndexReader reader, boolean delete) throws LuceneIndexException - { - boolean found = false; - try - { - TermDocs td = reader.termDocs(new Term("ID", nodeRef)); - while (td.next()) - { - int doc = td.doc(); - Document document = reader.document(doc); - // Exclude all containers except the root (which is also a node!) - Field path = document.getField("PATH"); - if (path == null || path.stringValue().length() == 0) - { - found = true; - if (delete) - { - reader.deleteDocument(doc); - } - else - { - break; - } - } - } - td.close(); - } - catch (IOException e) - { - throw new LuceneIndexException("Failed to delete container and below for " + nodeRef, e); - } - return found; - } - /** the maximum transformation time to allow atomically, defaulting to 20ms */ protected long maxAtomicTransformationTime = 20; diff --git a/source/java/org/alfresco/repo/search/impl/lucene/FilterIndexReaderByStringId.java b/source/java/org/alfresco/repo/search/impl/lucene/FilterIndexReaderByStringId.java index 2eb791e2bc..3d21cf09eb 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/FilterIndexReaderByStringId.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/FilterIndexReaderByStringId.java @@ -120,20 +120,32 @@ public class FilterIndexReaderByStringId extends FilterIndexReader } else { - TermQuery query = new TermQuery(new Term("ID", stringRef)); - Hits hits = searcher.search(query); - if (hits.length() > 0) + boolean found = false; + TermDocs td = in.termDocs(new Term("LEAFID", stringRef)); + while (td.next()) { - for (int i = 0; i < hits.length(); i++) + deletedDocuments.set(td.doc()); + found = true; + } + td.close(); + // For backward compatibility, use old method of locating non-container docs + if (!found) + { + TermQuery query = new TermQuery(new Term("ID", stringRef)); + Hits hits = searcher.search(query); + if (hits.length() > 0) { - Document doc = hits.doc(i); - // Exclude all containers except the root (which is also a node!) - Field path = doc.getField("PATH"); - if (path == null || path.stringValue().length() == 0) + for (int i = 0; i < hits.length(); i++) { - deletedDocuments.set(hits.id(i)); - // There should only be one thing to delete - // break; + Document doc = hits.doc(i); + // Exclude all containers except the root (which is also a node!) + Field path = doc.getField("PATH"); + if (path == null || path.stringValue().length() == 0) + { + deletedDocuments.set(hits.id(i)); + // There should only be one thing to delete + // break; + } } } } diff --git a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java index 1408bad338..5d5220f821 100644 --- a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java +++ b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2011 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -20,6 +20,7 @@ package org.alfresco.repo.security.person; import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -28,10 +29,12 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; +import org.alfresco.query.CannedQuery; import org.alfresco.query.CannedQueryFactory; import org.alfresco.query.CannedQueryResults; import org.alfresco.query.PagingRequest; @@ -46,9 +49,9 @@ import org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy; import org.alfresco.repo.node.NodeServicePolicies.OnUpdatePropertiesPolicy; import org.alfresco.repo.node.getchildren.FilterProp; import org.alfresco.repo.node.getchildren.FilterPropString; +import org.alfresco.repo.node.getchildren.FilterPropString.FilterTypeString; import org.alfresco.repo.node.getchildren.GetChildrenCannedQuery; import org.alfresco.repo.node.getchildren.GetChildrenCannedQueryFactory; -import org.alfresco.repo.node.getchildren.FilterPropString.FilterTypeString; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.search.SearcherException; @@ -59,16 +62,16 @@ import org.alfresco.repo.security.permissions.PermissionServiceSPI; import org.alfresco.repo.tenant.TenantDomainMismatchException; import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; -import org.alfresco.repo.transaction.TransactionListenerAdapter; -import org.alfresco.repo.transaction.TransactionalResourceHelper; import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.repo.transaction.TransactionListenerAdapter; +import org.alfresco.repo.transaction.TransactionalResourceHelper; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.admin.RepoAdminService; -import org.alfresco.service.cmr.admin.RepoUsageStatus; import org.alfresco.service.cmr.admin.RepoUsage.UsageType; +import org.alfresco.service.cmr.admin.RepoUsageStatus; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.invitation.InvitationException; import org.alfresco.service.cmr.model.FileFolderService; @@ -78,6 +81,9 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.TemplateService; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.cmr.search.LimitBy; +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.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; @@ -161,7 +167,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per private JavaBehaviour beforeDeleteNodeValidationBehaviour; private boolean homeFolderCreationEager; - + static { Set props = new HashSet(); @@ -1192,43 +1198,59 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per ParameterCheck.mandatory("pagingRequest", pagingRequest); Long start = (logger.isDebugEnabled() ? System.currentTimeMillis() : null); - - NodeRef contextNodeRef = getPeopleContainer(); - - Set childTypeQNames = new HashSet(1); - childTypeQNames.add(ContentModel.TYPE_PERSON); - - // get canned query - GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory)cannedQueryRegistry.getNamedObject(CANNED_QUERY_PEOPLE_LIST); - - List filterProps = null; - if (stringPropFilters != null) + + // TODO Remove this ALF-14127 hot fix code (calling nonCannedGetPeopleQuery(...) once this canned query does not fetch all rows from the database, + // which is very slow when there are a lot of users. 10,000 user takes about 4 seconds. The customer has 90,000. + CannedQueryResults cqResults = null; + String searchValue = null; + if (filterIgnoreCase && pagingRequest != null && pagingRequest.getQueryExecutionId() == null && pagingRequest.getSkipCount() == 0) { - filterProps = new ArrayList(stringPropFilters.size()); - for (Pair filterProp : stringPropFilters) - { - String filterStr = filterProp.getSecond(); - if ((filterStr == null) || (filterStr.equals("")) || (filterStr.equals("*"))) - { - // The wildcard means no filtering is needed on this property - continue; - } - else if (filterStr.endsWith("*")) - { - // The trailing * is implicit - filterStr = filterStr.substring(0, filterStr.length()-1); - } - - // Turn this into a canned query filter - filterProps.add(new FilterPropString(filterProp.getFirst(), filterStr, (filterIgnoreCase ? FilterTypeString.STARTSWITH_IGNORECASE : FilterTypeString.STARTSWITH))); - } + searchValue = getSearchOnNameValue(stringPropFilters); } + if (searchValue != null) + { + cqResults = nonCannedGetPeopleQuery(searchValue, pagingRequest); + } + else + { + NodeRef contextNodeRef = getPeopleContainer(); + + Set childTypeQNames = new HashSet(1); + childTypeQNames.add(ContentModel.TYPE_PERSON); + + // get canned query + GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory)cannedQueryRegistry.getNamedObject(CANNED_QUERY_PEOPLE_LIST); + + List filterProps = null; + if (stringPropFilters != null) + { + filterProps = new ArrayList(stringPropFilters.size()); + for (Pair filterProp : stringPropFilters) + { + String filterStr = filterProp.getSecond(); + if ((filterStr == null) || (filterStr.equals("")) || (filterStr.equals("*"))) + { + // The wildcard means no filtering is needed on this property + continue; + } + else if (filterStr.endsWith("*")) + { + // The trailing * is implicit + filterStr = filterStr.substring(0, filterStr.length()-1); + } + + // Turn this into a canned query filter + filterProps.add(new FilterPropString(filterProp.getFirst(), filterStr, (filterIgnoreCase ? FilterTypeString.STARTSWITH_IGNORECASE : FilterTypeString.STARTSWITH))); + } + } GetChildrenCannedQuery cq = (GetChildrenCannedQuery)getChildrenCannedQueryFactory.getCannedQuery(contextNodeRef, null, null, childTypeQNames, filterProps, sortProps, pagingRequest); - // execute canned query - final CannedQueryResults results = cq.execute(); + // execute canned query + cqResults = cq.execute(); + } + final CannedQueryResults results = cqResults; final List nodeRefs; if (results.getPageCount() > 0) { @@ -1303,6 +1325,258 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per }; } + /** + * If the search is on first, last and user name only with the same value, return that value, + * otherwise return null. + */ + // TODO Remove this ALF-14127 hot fix code once this canned query does not fetch all rows from the database. + private String getSearchOnNameValue(List> stringPropFilters) + { + String filter = null; + if (stringPropFilters != null && stringPropFilters.size() == 3) + { + // Does not check we don't have duplicates. + for (int i=0; i < 3; i++) + { + Pair pair = stringPropFilters.get(i); + if (i == 0) + { + filter = pair.getSecond().trim(); + if (filter == null || filter.length() == 0) + { + filter = null; + break; + } + } + + if ((i != 0 && !filter.equals(pair.getSecond().trim()) || !NAME_SEARCH_NAMES.contains(pair.getFirst()))) + { + filter = null; + break; + } + } + } + return filter; + } + + // TODO Remove this ALF-14127 hot fix code once this canned query does not fetch all rows from the database. + private static final List NAME_SEARCH_NAMES = Arrays.asList(new QName[] { + ContentModel.PROP_FIRSTNAME, ContentModel.PROP_LASTNAME, ContentModel.PROP_USERNAME}); + + /** + * Use Solr search based on code in org.alfresco.repo.jscript.People.getPeople(String, int) + */ + // TODO Remove this ALF-14127 hot fix code once this canned query does not fetch all rows from the database. + private CannedQueryResults nonCannedGetPeopleQuery(String filter, PagingRequest pagingRequest) + { + Long start = (logger.isDebugEnabled() ? System.currentTimeMillis() : null); + int maxResults = pagingRequest != null ? pagingRequest.getMaxItems() : Integer.MAX_VALUE; + if (maxResults <= 0) + { + maxResults = Integer.MAX_VALUE; + } + + String term = filter.replace("\\", "").replace("\"", ""); + StringTokenizer t = new StringTokenizer(term, " "); + int propIndex = term.indexOf(':'); + + SearchParameters params = new SearchParameters(); + params.addQueryTemplate("_PERSON", "|%firstName OR |%lastName OR |%userName"); + params.setDefaultFieldName("_PERSON"); + + StringBuilder query = new StringBuilder(256); + + query.append("TYPE:\"").append(ContentModel.TYPE_PERSON).append("\" AND ("); + + if (t.countTokens() == 1) + { + // single word with no field will go against _PERSON and expand + + // fts-alfresco property search i.e. location:"maidenhead" + query.append(term.substring(0, propIndex + 1)).append('"') + .append(term.substring(propIndex + 1)); + if (propIndex > 0) + { + query.append('"'); + } + else + { + query.append("*\""); + } + } + else + { + // scan for non-fts-alfresco property search tokens + int nonFtsTokens = 0; + while (t.hasMoreTokens()) + { + if (t.nextToken().indexOf(':') == -1) + nonFtsTokens++; + } + t = new StringTokenizer(term, " "); + + // multiple terms supplied - look for first and second name etc. + // assume first term is first name, any more are second i.e. + // "Fraun van de Wiels" + // also allow fts-alfresco property search to reduce results + params.setDefaultOperator(SearchParameters.Operator.AND); + boolean firstToken = true; + boolean tokenSurname = false; + boolean propertySearch = false; + while (t.hasMoreTokens()) + { + term = t.nextToken(); + if (!propertySearch && term.indexOf(':') == -1) + { + if (nonFtsTokens == 1) + { + // simple search: first name, last name and username + // starting with term + query.append("_PERSON:\""); + query.append(term); + query.append("*\" "); + } + else + { + if (firstToken) + { + query.append("firstName:\""); + query.append(term); + query.append("*\" "); + + firstToken = false; + } + else + { + if (tokenSurname) + { + query.append("OR "); + } + query.append("lastName:\""); + query.append(term); + query.append("*\" "); + + tokenSurname = true; + } + } + } + else + { + // fts-alfresco property search i.e. "location:maidenhead" + propIndex = term.indexOf(':'); + query.append(term.substring(0, propIndex + 1)).append('"') + .append(term.substring(propIndex + 1)).append('"'); + + propertySearch = true; + } + } + } + query.append(")"); + + // define the search parameters + params.setLanguage(SearchService.LANGUAGE_FTS_ALFRESCO); + params.addStore(this.storeRef); + params.setQuery(query.toString()); + if (maxResults > 0) + { + params.setLimitBy(LimitBy.FINAL_SIZE); + params.setLimit(maxResults); + } + + ResultSet results = null; + List resultNodeRefs = null; + try + { + results = searchService.query(params); + resultNodeRefs = results.getNodeRefs(); + } + catch (Throwable err) + { + resultNodeRefs = Collections.emptyList(); + + // hide query parse error from users + if (logger.isDebugEnabled()) + logger.debug("Failed to execute people search: " + query.toString(), err); + } + finally + { + if (results != null) + { + results.close(); + } + } + + // Turn NodeRefs into a single page of results. + final List nodRefs = resultNodeRefs; + CannedQueryResults cqResults = new CannedQueryResults() + { + @Override + public CannedQuery getOriginatingQuery() + { + return null; + } + + @Override + public String getQueryExecutionId() + { + return null; + } + + @Override + public Pair getTotalResultCount() + { + int size = nodRefs.size(); + return new Pair(size, size); + } + + @Override + public int getPagedResultCount() + { + return nodRefs.size(); + } + + @Override + public int getPageCount() + { + return 1; + } + + @Override + public NodeRef getSingleResult() + { + if (nodRefs.size() != 1) + { + throw new IllegalStateException( + "There must be exactly one page of one result available."); + } + return nodRefs.get(0); + } + + @Override + public List getPage() + { + return nodRefs; + } + + @Override + public List> getPages() + { + return Collections.singletonList(getPage()); + } + + @Override + public boolean hasMoreItems() + { + return false; + } + }; + if (logger.isDebugEnabled()) + { + logger.debug("nonCannedGetPeopleQuery(\""+filter+"\", "+maxResults+") "+cqResults.getTotalResultCount()+" in "+(System.currentTimeMillis()-start)+" msecs "); + } + return cqResults; + } + /** * {@inheritDoc} */ @@ -1668,8 +1942,8 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per public int countPeople() { - NodeRef peopleContainer = getPeopleContainer(); - return nodeService.countChildAssocs(peopleContainer, true); + NodeRef peopleContainer = getPeopleContainer(); + return nodeService.countChildAssocs(peopleContainer, true); } /** diff --git a/source/java/org/alfresco/repo/site/SiteServiceImpl.java b/source/java/org/alfresco/repo/site/SiteServiceImpl.java index 116e3ed815..66ab9d55a9 100644 --- a/source/java/org/alfresco/repo/site/SiteServiceImpl.java +++ b/source/java/org/alfresco/repo/site/SiteServiceImpl.java @@ -561,15 +561,17 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic } // Create the site's groups - String siteGroup = authorityService.createAuthority( - AuthorityType.GROUP, getSiteGroup(shortName, false), shortName, shareZones); + String siteGroupShortName = getSiteGroup(shortName, false); + String siteGroup = authorityService.createAuthority(AuthorityType.GROUP, siteGroupShortName, + siteGroupShortName, shareZones); QName siteType = directNodeService.getType(siteNodeRef); Set permissions = permissionService.getSettablePermissions(siteType); for (String permission : permissions) { // Create a group for the permission - String permissionGroup = authorityService.createAuthority(AuthorityType.GROUP, getSiteRoleGroup( - shortName, permission, false), shortName, shareZones); + String permissionGroupShortName = getSiteRoleGroup(shortName, permission, false); + String permissionGroup = authorityService.createAuthority(AuthorityType.GROUP, + permissionGroupShortName, permissionGroupShortName, shareZones); authorityService.addAuthority(siteGroup, permissionGroup); // add any supplied memberships to it diff --git a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImplTest.java b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImplTest.java index 91ecab05d3..1bfbfa4f6a 100644 --- a/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImplTest.java +++ b/source/java/org/alfresco/repo/transfer/RepoTransferReceiverImplTest.java @@ -133,51 +133,67 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest public void testDelete() { - setDefaultRollback(false); - String uuid = GUID.generate(); - ChildAssociationRef childAssoc; - startNewTransaction(); - try - { - ResultSet rs = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_XPATH, - "/app:company_home"); - assertEquals(1, rs.length()); - NodeRef companyHome = rs.getNodeRef(0); - Map props = new HashMap(); - props.put(ContentModel.PROP_NAME, uuid); - childAssoc = nodeService.createNode(companyHome, ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.APP_MODEL_1_0_URI, uuid), ContentModel.TYPE_CONTENT, props); - } - finally - { - endTransaction(); - } + log.debug("start testDelete"); - startNewTransaction(); - try + final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); + final String uuid = GUID.generate(); + class TestContext { - nodeService.deleteNode(childAssoc.getChildRef()); - } - finally - { - endTransaction(); - } + ChildAssociationRef childAssoc; + }; - startNewTransaction(); - try + RetryingTransactionCallback setupCB = new RetryingTransactionCallback() { - log.debug("Test that original node no longer exists..."); - assertFalse(nodeService.exists(childAssoc.getChildRef())); - log.debug("PASS - Original node no longer exists."); - NodeRef archiveNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, childAssoc.getChildRef().getId()); - log.debug("Test that archive node exists..."); - assertTrue(nodeService.exists(archiveNodeRef)); - log.debug("PASS - Archive node exists."); - } - finally + + @Override + public TestContext execute() throws Throwable + { + TestContext tc = new TestContext(); + ResultSet rs = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_XPATH, + "/app:company_home"); + assertEquals(1, rs.length()); + NodeRef companyHome = rs.getNodeRef(0); + Map props = new HashMap(); + props.put(ContentModel.PROP_NAME, uuid); + tc.childAssoc = nodeService.createNode(companyHome, ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.APP_MODEL_1_0_URI, uuid), ContentModel.TYPE_CONTENT, props); + return tc; + } + }; + + final TestContext tc = tran.doInTransaction(setupCB, false, true); + + RetryingTransactionCallback deleteCB = new RetryingTransactionCallback() { - endTransaction(); - } + + @Override + public Void execute() throws Throwable + { + nodeService.deleteNode(tc.childAssoc.getChildRef()); + return null; + } + }; + + tran.doInTransaction(deleteCB, false, true); + + RetryingTransactionCallback validateCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + log.debug("Test that original node no longer exists..."); + assertFalse(nodeService.exists(tc.childAssoc.getChildRef())); + log.debug("PASS - Original node no longer exists."); + NodeRef archiveNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, tc.childAssoc.getChildRef().getId()); + log.debug("Test that archive node exists..."); + assertTrue(nodeService.exists(archiveNodeRef)); + log.debug("PASS - Archive node exists."); + return null; + } + }; + + tran.doInTransaction(validateCB, false, true); } @@ -185,9 +201,9 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest * Tests start and end with regard to locking. * @throws Exception */ - public void testStartAndEnd() throws Exception + public void DISABLED_testStartAndEnd() throws Exception { - log.info("testStartAndEnd"); + log.debug("start testStartAndEnd"); RetryingTransactionHelper trx = transactionService.getRetryingTransactionHelper(); @@ -199,6 +215,7 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest { log.debug("about to call start"); String transferId = receiver.start("1234", true, receiver.getVersion()); + File stagingFolder = null; try { @@ -267,6 +284,7 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest for (int i = 0; i < 5; i++) { log.info("test iteration:" + i); + trx.doInTransaction(cb, false, true); } } @@ -282,9 +300,9 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest * Going to cut down the timeout to a very short period, the lock should expire * @throws Exception */ - public void testLockTimeout() throws Exception + public void DISABLED_testLockTimeout() throws Exception { - log.info("testStartAndEnd"); + log.info("start testLockTimeout"); RetryingTransactionHelper trx = transactionService.getRetryingTransactionHelper(); @@ -310,16 +328,8 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest log.debug("about to call start"); String transferId = receiver.start("1234", true, receiver.getVersion()); Thread.sleep(1000); - try - { - receiver.saveSnapshot(transferId, null); - fail("did not timeout"); - } - catch (TransferException te) - { - logger.debug("expected to timeout", te); - // expect to go here with a timeout - } + receiver.saveSnapshot(transferId, null); + fail("did not timeout"); return null; } }; @@ -343,18 +353,30 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest trx.doInTransaction(startWithoutAnythingElse, false, true); Thread.sleep(1000); } - trx.doInTransaction(slowTransfer, false, true); + try + { + trx.doInTransaction(slowTransfer, false, true); + } + catch (Exception e) + { + // Expect to go here. + } } finally { receiver.setLockRefreshTime(lockRefreshTime); receiver.setLockTimeOut(lockTimeOut); } + + log.info("end testLockTimeout"); } public void testSaveContent() throws Exception { - log.info("testSaveContent"); + log.info("start testSaveContent"); + + final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); + startNewTransaction(); try { @@ -380,7 +402,10 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest public void testSaveSnapshot() throws Exception { - log.info("testSaveSnapshot"); + log.info("start testSaveSnapshot"); + + final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); + startNewTransaction(); try { @@ -388,7 +413,7 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest File snapshotFile = null; try { - TransferManifestNode node = createContentNode(transferId); + TransferManifestNode node = createContentNode(); List nodes = new ArrayList(); nodes.add(node); String snapshot = createSnapshot(nodes); @@ -417,140 +442,252 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest public void testBasicCommit() throws Exception { - log.info("testBasicCommit"); - startNewTransaction(); - TransferManifestNode node = null; - - try + log.info("start testBasicCommit"); + + final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); + + class TestContext { - String transferId = receiver.start("1234", true, receiver.getVersion()); - try + TransferManifestNode node = null; + String transferId = null; + } + + RetryingTransactionCallback setupCB = new RetryingTransactionCallback() + { + @Override + public TestContext execute() throws Throwable { - node = createContentNode(transferId); + TestContext tc = new TestContext(); + tc.node = createContentNode(); + return tc; + } + }; + + final TestContext tc = tran.doInTransaction(setupCB, false, true); + + RetryingTransactionCallback doPrepareCB = new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + tc.transferId = receiver.start("1234", true, receiver.getVersion()); + List nodes = new ArrayList(); - nodes.add(node); + nodes.add(tc.node); String snapshot = createSnapshot(nodes); - receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8")); - receiver.saveContent(transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes)); - receiver.commit(transferId); - + receiver.saveSnapshot(tc.transferId, new StringInputStream(snapshot, "UTF-8")); + receiver.saveContent(tc.transferId, tc.node.getUuid(), new ByteArrayInputStream(dummyContentBytes)); + + return null; } - catch (Exception ex) - { - receiver.end(transferId); - throw ex; - } - } - finally + }; + + RetryingTransactionCallback doCommitCB = new RetryingTransactionCallback() { - endTransaction(); - } + @Override + public Void execute() throws Throwable + { + receiver.commit(tc.transferId); - startNewTransaction(); + return null; + } + }; + + RetryingTransactionCallback doEndCB = new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + receiver.end(tc.transferId); + return null; + } + }; + try { - assertTrue(nodeService.exists(node.getNodeRef())); - nodeService.deleteNode(node.getNodeRef()); + tran.doInTransaction(doPrepareCB, false, true); + tran.doInTransaction(doCommitCB, false, true); } finally { - endTransaction(); + if(tc.transferId != null) + { + tran.doInTransaction(doEndCB, false, true); + } } + + RetryingTransactionCallback doValidateCB = new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + assertTrue(nodeService.exists(tc.node.getNodeRef())); + nodeService.deleteNode(tc.node.getNodeRef()); + + return null; + } + }; + + tran.doInTransaction(doValidateCB, false, true); } + /** + * Test More Complex Commit + * + * @throws Exception + */ public void testMoreComplexCommit() throws Exception { - log.info("testMoreComplexCommit"); - List nodes = new ArrayList(); - TransferManifestNormalNode node1 = null; - TransferManifestNormalNode node2 = null; - TransferManifestNode node3 = null; - TransferManifestNode node4 = null; - TransferManifestNode node5 = null; - TransferManifestNode node6 = null; - TransferManifestNode node7 = null; - TransferManifestNode node8 = null; - TransferManifestNode node9 = null; - TransferManifestNode node10 = null; - TransferManifestNormalNode node11 = null; - TransferManifestNode node12 = null; - String transferId = null; + log.info("start testMoreComplexCommit"); + final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); + + class TestContext + { + List nodes = new ArrayList(); + TransferManifestNormalNode node1 = null; + TransferManifestNormalNode node2 = null; + TransferManifestNode node3 = null; + TransferManifestNode node4 = null; + TransferManifestNode node5 = null; + TransferManifestNode node6 = null; + TransferManifestNode node7 = null; + TransferManifestNode node8 = null; + TransferManifestNode node9 = null; + TransferManifestNode node10 = null; + TransferManifestNormalNode node11 = null; + TransferManifestNode node12 = null; + String transferId = null; + }; - startNewTransaction(); + RetryingTransactionCallback setupCB = new RetryingTransactionCallback() + { + @Override + public TestContext execute() throws Throwable + { + TestContext tc = new TestContext(); + + tc.node1 = createContentNode(); + tc.nodes.add(tc.node1); + tc.node2 = createContentNode(); + tc.nodes.add(tc.node2); + tc.node3 = createContentNode(); + tc.nodes.add(tc.node3); + tc.node4 = createContentNode(); + tc.nodes.add(tc.node4); + tc.node5 = createContentNode(); + tc.nodes.add(tc.node5); + tc.node6 = createContentNode(); + tc.nodes.add(tc.node6); + tc.node7 = createContentNode(); + tc.nodes.add(tc.node7); + tc.node8 = createFolderNode(); + tc.nodes.add(tc.node8); + tc.node9 = createFolderNode(); + tc.nodes.add(tc.node9); + tc.node10 = createFolderNode(); + tc.nodes.add(tc.node10); + tc.node11 = createFolderNode(); + tc.nodes.add(tc.node11); + tc.node12 = createFolderNode(); + tc.nodes.add(tc.node12); + + associatePeers(tc.node1, tc.node2); + moveNode(tc.node2, tc.node11); + + return tc; + } + }; + + final TestContext tc = tran.doInTransaction(setupCB, false, true); + + RetryingTransactionCallback doPrepareCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + tc.transferId = receiver.start("1234", true, receiver.getVersion()); + String snapshot = createSnapshot(tc.nodes); + + receiver.saveSnapshot(tc.transferId, new StringInputStream(snapshot, "UTF-8")); + + for (TransferManifestNode node : tc.nodes) + { + receiver.saveContent(tc.transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes)); + } + return null; + } + }; + + RetryingTransactionCallback doCommitCB = new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + log.info("testMoreComplexCommit - commit"); + receiver.commit(tc.transferId); + log.info("testMoreComplexCommit - commited"); + return null; + } + }; + RetryingTransactionCallback doEndCB = new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + // Needs to move elsewhere to allow other tests to pass. + receiver.end(tc.transferId); + return null; + } + }; + try { - transferId = receiver.start("1234", true, receiver.getVersion()); - node1 = createContentNode(transferId); - nodes.add(node1); - node2 = createContentNode(transferId); - nodes.add(node2); - node3 = createContentNode(transferId); - nodes.add(node3); - node4 = createContentNode(transferId); - nodes.add(node4); - node5 = createContentNode(transferId); - nodes.add(node5); - node6 = createContentNode(transferId); - nodes.add(node6); - node7 = createContentNode(transferId); - nodes.add(node7); - node8 = createFolderNode(transferId); - nodes.add(node8); - node9 = createFolderNode(transferId); - nodes.add(node9); - node10 = createFolderNode(transferId); - nodes.add(node10); - node11 = createFolderNode(transferId); - nodes.add(node11); - node12 = createFolderNode(transferId); - nodes.add(node12); - - associatePeers(node1, node2); - moveNode(node2, node11); - - String snapshot = createSnapshot(nodes); - - receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8")); - - for (TransferManifestNode node : nodes) - { - receiver.saveContent(transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes)); - } - log.info("testMoreComplexCommit - commit"); - receiver.commit(transferId); - log.info("testMoreComplexCommit - commited"); - + tran.doInTransaction(doPrepareCB, false, true); + tran.doInTransaction(doCommitCB, false, true); } finally { - log.info("testMoreComplexCommit - end"); - receiver.end(transferId); - endTransaction(); - } - - startNewTransaction(); - try - { - log.info("testMoreComplexCommit - validate nodes"); - assertTrue(nodeService.getAspects(node1.getNodeRef()).contains(ContentModel.ASPECT_ATTACHABLE)); - assertFalse(nodeService.getSourceAssocs(node2.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS).isEmpty()); - for (TransferManifestNode node : nodes) + if(tc.transferId != null) { - assertTrue(nodeService.exists(node.getNodeRef())); + tran.doInTransaction(doEndCB, false, true); } } - finally + + RetryingTransactionCallback validateCB = new RetryingTransactionCallback() { - endTransaction(); - } + @Override + public Void execute() throws Throwable + { + log.info("testMoreComplexCommit - validate nodes"); + assertTrue(nodeService.getAspects(tc.node1.getNodeRef()).contains(ContentModel.ASPECT_ATTACHABLE)); + assertFalse(nodeService.getSourceAssocs(tc.node2.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS).isEmpty()); + for (TransferManifestNode node : tc.nodes) + { + assertTrue(nodeService.exists(node.getNodeRef())); + } + + return null; + } + }; + tran.doInTransaction(validateCB, false, true); } + /** + * Test Node Delete And Restore + * + * @throws Exception + */ @SuppressWarnings("unchecked") public void testNodeDeleteAndRestore() throws Exception { - TransferServicePolicies.OnEndInboundTransferPolicy mockedPolicyHandler = + log.info("start testNodeDeleteAndRestore"); + + final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); + + final TransferServicePolicies.OnEndInboundTransferPolicy mockedPolicyHandler = mock(TransferServicePolicies.OnEndInboundTransferPolicy.class); policyComponent.bindClassBehaviour( @@ -558,220 +695,359 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest TransferModel.TYPE_TRANSFER_RECORD, new JavaBehaviour(mockedPolicyHandler, "onEndInboundTransfer", NotificationFrequency.EVERY_EVENT)); - log.info("testNodeDeleteAndRestore"); - - setDefaultRollback(true); - startNewTransaction(); - String transferId = receiver.start("1234", true, receiver.getVersion()); - - List nodes = new ArrayList(); - TransferManifestNormalNode node1 = createContentNode(transferId); - nodes.add(node1); - TransferManifestNormalNode node2 = createContentNode(transferId); - nodes.add(node2); - TransferManifestNode node3 = createContentNode(transferId); - nodes.add(node3); - TransferManifestNode node4 = createContentNode(transferId); - nodes.add(node4); - TransferManifestNode node5 = createContentNode(transferId); - nodes.add(node5); - TransferManifestNode node6 = createContentNode(transferId); - nodes.add(node6); - TransferManifestNode node7 = createContentNode(transferId); - nodes.add(node7); - TransferManifestNode node8 = createFolderNode(transferId); - nodes.add(node8); - TransferManifestNode node9 = createFolderNode(transferId); - nodes.add(node9); - TransferManifestNode node10 = createFolderNode(transferId); - nodes.add(node10); - TransferManifestNormalNode node11 = createFolderNode(transferId); - nodes.add(node11); - TransferManifestNode node12 = createFolderNode(transferId); - nodes.add(node12); - - associatePeers(node1, node2); - moveNode(node2, node11); - - TransferManifestDeletedNode deletedNode8 = createDeletedNode(node8); - TransferManifestDeletedNode deletedNode2 = createDeletedNode(node2); - TransferManifestDeletedNode deletedNode11 = createDeletedNode(node11); - - endTransaction(); - - this.setDefaultRollback(false); - startNewTransaction(); - try + class TestContext { - String snapshot = createSnapshot(nodes); - log.debug(snapshot); - receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8")); - - for (TransferManifestNode node : nodes) - { - receiver.saveContent(transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes)); - } - receiver.commit(transferId); - - assertTrue(nodeService.getAspects(node1.getNodeRef()).contains(ContentModel.ASPECT_ATTACHABLE)); - assertFalse(nodeService.getSourceAssocs(node2.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS).isEmpty()); - - ArgumentCaptor transferIdCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor createdNodesCaptor = ArgumentCaptor.forClass(Set.class); - ArgumentCaptor updatedNodesCaptor = ArgumentCaptor.forClass(Set.class); - ArgumentCaptor deletedNodesCaptor = ArgumentCaptor.forClass(Set.class); - verify(mockedPolicyHandler, times(1)).onEndInboundTransfer(transferIdCaptor.capture(), - createdNodesCaptor.capture(), updatedNodesCaptor.capture(), deletedNodesCaptor.capture()); - assertEquals(transferId, transferIdCaptor.getValue()); - Set capturedCreatedNodes = createdNodesCaptor.getValue(); - assertEquals(nodes.size(), capturedCreatedNodes.size()); - - for (TransferManifestNode node : nodes) - { - assertTrue(nodeService.exists(node.getNodeRef())); - assertTrue(capturedCreatedNodes.contains(node.getNodeRef())); - } - } - finally - { - endTransaction(); - } - - reset(mockedPolicyHandler); + String transferId; + TransferManifestNormalNode node1; + TransferManifestNormalNode node2; + TransferManifestNode node3; + TransferManifestNode node4; + TransferManifestNode node5; + TransferManifestNode node6; + TransferManifestNode node7; + TransferManifestNode node8; + TransferManifestNode node9; + TransferManifestNode node10; + TransferManifestNormalNode node11; + TransferManifestNode node12; + TransferManifestDeletedNode deletedNode8; + TransferManifestDeletedNode deletedNode2; + TransferManifestDeletedNode deletedNode11; + List nodes; + String errorMsgId; + }; - startNewTransaction(); - try + RetryingTransactionCallback setupCB = new RetryingTransactionCallback() { - // Now delete nodes 8, 2, and 11 (11 and 2 are parent/child) - transferId = receiver.start("1234", true, receiver.getVersion()); - String snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] { deletedNode8, deletedNode2, - deletedNode11 })); - log.debug(snapshot); - receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8")); - receiver.commit(transferId); - - ArgumentCaptor transferIdCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor createdNodesCaptor = ArgumentCaptor.forClass(Set.class); - ArgumentCaptor updatedNodesCaptor = ArgumentCaptor.forClass(Set.class); - ArgumentCaptor deletedNodesCaptor = ArgumentCaptor.forClass(Set.class); - verify(mockedPolicyHandler, times(1)).onEndInboundTransfer(transferIdCaptor.capture(), - createdNodesCaptor.capture(), updatedNodesCaptor.capture(), deletedNodesCaptor.capture()); - assertEquals(transferId, transferIdCaptor.getValue()); - Set capturedDeletedNodes = deletedNodesCaptor.getValue(); - assertEquals(3, capturedDeletedNodes.size()); - assertTrue(capturedDeletedNodes.contains(deletedNode8.getNodeRef())); - assertTrue(capturedDeletedNodes.contains(deletedNode2.getNodeRef())); - assertTrue(capturedDeletedNodes.contains(deletedNode11.getNodeRef())); - } - finally - { - endTransaction(); - } - - startNewTransaction(); - try - { - log.debug("Test success of transfer..."); - TransferProgress progress = receiver.getProgressMonitor().getProgress(transferId); - assertEquals(TransferProgress.Status.COMPLETE, progress.getStatus()); - - NodeRef archiveNode8 = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, node8.getNodeRef().getId()); - NodeRef archiveNode2 = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, node2.getNodeRef().getId()); - NodeRef archiveNode11 = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, node11.getNodeRef().getId()); - - assertTrue(nodeService.exists(archiveNode8)); - assertTrue(nodeService.hasAspect(archiveNode8, ContentModel.ASPECT_ARCHIVED)); - log.debug("Successfully tested existence of archive node: " + archiveNode8); - - assertTrue(nodeService.exists(archiveNode2)); - assertTrue(nodeService.hasAspect(archiveNode2, ContentModel.ASPECT_ARCHIVED)); - log.debug("Successfully tested existence of archive node: " + archiveNode2); - - assertTrue(nodeService.exists(archiveNode11)); - assertTrue(nodeService.hasAspect(archiveNode11, ContentModel.ASPECT_ARCHIVED)); - log.debug("Successfully tested existence of archive node: " + archiveNode11); - - log.debug("Successfully tested existence of all archive nodes"); - - log.debug("Testing existence of original node: " + node8.getNodeRef()); - assertFalse(nodeService.exists(node8.getNodeRef())); - - log.debug("Testing existence of original node: " + node2.getNodeRef()); - assertFalse(nodeService.exists(node2.getNodeRef())); - - log.debug("Testing existence of original node: " + node11.getNodeRef()); - assertFalse(nodeService.exists(node11.getNodeRef())); - - log.debug("Successfully tested non-existence of all original nodes"); - - log.debug("Progress indication: " + progress.getCurrentPosition() + "/" + progress.getEndPosition()); - } - finally - { - endTransaction(); - } - System.out.println("Now try to restore orphan node 2."); - - reset(mockedPolicyHandler); - - String errorMsgId = null; - startNewTransaction(); - try - { - // try to restore node 2. Expect an "orphan" failure, since its parent (node11) is deleted - transferId = receiver.start("1234", true, receiver.getVersion()); - String snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] { node2 })); - log.debug(snapshot); - receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8")); - receiver.saveContent(transferId, node2.getUuid(), new ByteArrayInputStream(dummyContentBytes)); - try + @Override + public TestContext execute() throws Throwable { - receiver.commit(transferId); - fail("Expected an exception"); + TestContext tc = new TestContext(); + + tc.nodes = new ArrayList(); + tc.node1 = createContentNode(); + tc.nodes.add(tc.node1); + tc.node2 = createContentNode(); + tc.nodes.add(tc.node2); + tc.node3 = createContentNode(); + tc.nodes.add(tc.node3); + tc.node4 = createContentNode(); + tc.nodes.add(tc.node4); + tc.node5 = createContentNode(); + tc.nodes.add(tc.node5); + tc.node6 = createContentNode(); + tc.nodes.add(tc.node6); + tc.node7 = createContentNode(); + tc.nodes.add(tc.node7); + tc.node8 = createFolderNode(); + tc.nodes.add(tc.node8); + tc.node9 = createFolderNode(); + tc.nodes.add(tc.node9); + tc.node10 = createFolderNode(); + tc.nodes.add(tc.node10); + tc.node11 = createFolderNode(); + tc.nodes.add(tc.node11); + tc.node12 = createFolderNode(); + tc.nodes.add(tc.node12); + + associatePeers(tc.node1, tc.node2); + moveNode(tc.node2, tc.node11); + + tc.deletedNode8 = createDeletedNode(tc.node8); + tc.deletedNode2 = createDeletedNode(tc.node2); + tc.deletedNode11 = createDeletedNode(tc.node11); + + return tc; } - catch (TransferException ex) + }; + + final TestContext tc = tran.doInTransaction(setupCB, false, true); + + RetryingTransactionCallback doFirstPrepareCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable { - // Expected - errorMsgId = ex.getMsgId(); + tc.transferId = receiver.start("1234", true, receiver.getVersion()); + String snapshot = createSnapshot(tc.nodes); + log.debug(snapshot); + receiver.saveSnapshot(tc.transferId, new StringInputStream(snapshot, "UTF-8")); + + for (TransferManifestNode node : tc.nodes) + { + receiver.saveContent(tc.transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes)); + } + + return null; + } + }; + + RetryingTransactionCallback doCommitCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + receiver.commit(tc.transferId); + + return null; + } + }; + RetryingTransactionCallback doEndCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + // Needs to move elsewhere to allow other tests to pass. + receiver.end(tc.transferId); + return null; + } + }; + + RetryingTransactionCallback validateFirstCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + assertTrue(nodeService.getAspects(tc.node1.getNodeRef()).contains(ContentModel.ASPECT_ATTACHABLE)); + assertFalse(nodeService.getSourceAssocs(tc.node2.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS).isEmpty()); ArgumentCaptor transferIdCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor createdNodesCaptor = ArgumentCaptor.forClass(Set.class); ArgumentCaptor updatedNodesCaptor = ArgumentCaptor.forClass(Set.class); ArgumentCaptor deletedNodesCaptor = ArgumentCaptor.forClass(Set.class); - verify(mockedPolicyHandler, times(1)).onEndInboundTransfer(transferIdCaptor.capture(), - createdNodesCaptor.capture(), updatedNodesCaptor.capture(), deletedNodesCaptor.capture()); - - assertEquals(transferId, transferIdCaptor.getValue()); - assertTrue(createdNodesCaptor.getValue().isEmpty()); - assertTrue(updatedNodesCaptor.getValue().isEmpty()); - assertTrue(deletedNodesCaptor.getValue().isEmpty()); - } - } - catch (Exception ex) - { - receiver.end(transferId); - throw ex; - } - finally - { - endTransaction(); - } + createdNodesCaptor.capture(), + updatedNodesCaptor.capture(), + deletedNodesCaptor.capture()); + assertEquals(tc.transferId, transferIdCaptor.getValue()); + Set capturedCreatedNodes = createdNodesCaptor.getValue(); + assertEquals(tc.nodes.size(), capturedCreatedNodes.size()); - startNewTransaction(); + for (TransferManifestNode node : tc.nodes) + { + assertTrue(nodeService.exists(node.getNodeRef())); + assertTrue(capturedCreatedNodes.contains(node.getNodeRef())); + } + return null; + } + }; + + + /** + * First transfer test here + */ + reset(mockedPolicyHandler); try { - TransferProgress progress = receiver.getProgressMonitor().getProgress(transferId); - assertEquals(TransferProgress.Status.ERROR, progress.getStatus()); - log.debug("Progress indication: " + progress.getCurrentPosition() + "/" + progress.getEndPosition()); - assertNotNull("Progress error", progress.getError()); - assertTrue(progress.getError() instanceof Exception); - assertTrue(errorMsgId, errorMsgId.contains("orphan")); + tran.doInTransaction(doFirstPrepareCB, false, true); + tran.doInTransaction(doCommitCB, false, true); + tran.doInTransaction(validateFirstCB, false, true); } finally { - endTransaction(); + if(tc.transferId != null) + { + tran.doInTransaction(doEndCB, false, true); + } } + + /** + * Second transfer this time with some deleted nodes, + * + * nodes 8, 2, and 11 (11 and 2 are parent/child) + */ + reset(mockedPolicyHandler); + + logger.debug("part 2 - transfer some deleted nodes"); + + RetryingTransactionCallback doSecondPrepareCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + // Now delete nodes 8, 2, and 11 (11 and 2 are parent/child) + tc.transferId = receiver.start("1234", true, receiver.getVersion()); + String snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] { tc.deletedNode8, + tc.deletedNode2, + tc.deletedNode11 })); + log.debug(snapshot); + receiver.saveSnapshot(tc.transferId, new StringInputStream(snapshot, "UTF-8")); + + return null; + } + }; + + RetryingTransactionCallback validateSecondCB = new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + ArgumentCaptor transferIdCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor createdNodesCaptor = ArgumentCaptor.forClass(Set.class); + ArgumentCaptor updatedNodesCaptor = ArgumentCaptor.forClass(Set.class); + ArgumentCaptor deletedNodesCaptor = ArgumentCaptor.forClass(Set.class); + verify(mockedPolicyHandler, times(1)).onEndInboundTransfer(transferIdCaptor.capture(), + createdNodesCaptor.capture(), + updatedNodesCaptor.capture(), + deletedNodesCaptor.capture()); + assertEquals(tc.transferId, transferIdCaptor.getValue()); + Set capturedDeletedNodes = deletedNodesCaptor.getValue(); + assertEquals(3, capturedDeletedNodes.size()); + assertTrue(capturedDeletedNodes.contains(tc.deletedNode8.getNodeRef())); + assertTrue(capturedDeletedNodes.contains(tc.deletedNode2.getNodeRef())); + assertTrue(capturedDeletedNodes.contains(tc.deletedNode11.getNodeRef())); + + log.debug("Test success of transfer..."); + TransferProgress progress = receiver.getProgressMonitor().getProgress(tc.transferId); + assertEquals(TransferProgress.Status.COMPLETE, progress.getStatus()); + + NodeRef archiveNode8 = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, tc.node8.getNodeRef().getId()); + NodeRef archiveNode2 = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, tc.node2.getNodeRef().getId()); + NodeRef archiveNode11 = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, tc.node11.getNodeRef().getId()); + + assertTrue(nodeService.exists(archiveNode8)); + assertTrue(nodeService.hasAspect(archiveNode8, ContentModel.ASPECT_ARCHIVED)); + log.debug("Successfully tested existence of archive node: " + archiveNode8); + + assertTrue(nodeService.exists(archiveNode2)); + assertTrue(nodeService.hasAspect(archiveNode2, ContentModel.ASPECT_ARCHIVED)); + log.debug("Successfully tested existence of archive node: " + archiveNode2); + + assertTrue(nodeService.exists(archiveNode11)); + assertTrue(nodeService.hasAspect(archiveNode11, ContentModel.ASPECT_ARCHIVED)); + log.debug("Successfully tested existence of archive node: " + archiveNode11); + + log.debug("Successfully tested existence of all archive nodes"); + + log.debug("Testing existence of original node: " + tc.node8.getNodeRef()); + assertFalse(nodeService.exists(tc.node8.getNodeRef())); + + log.debug("Testing existence of original node: " + tc.node2.getNodeRef()); + assertFalse(nodeService.exists(tc.node2.getNodeRef())); + + log.debug("Testing existence of original node: " + tc.node11.getNodeRef()); + assertFalse(nodeService.exists(tc.node11.getNodeRef())); + + log.debug("Successfully tested non-existence of all original nodes"); + + log.debug("Progress indication: " + progress.getCurrentPosition() + "/" + progress.getEndPosition()); + return null; + } + }; + + try + { + tran.doInTransaction(doSecondPrepareCB, false, true); + tran.doInTransaction(doCommitCB, false, true); + tran.doInTransaction(validateSecondCB, false, true); + } + finally + { + if(tc.transferId != null) + { + tran.doInTransaction(doEndCB, false, true); + } + } + + logger.debug("part 3 - restore orphan node which should fail"); + System.out.println("Now try to restore orphan node 2."); + /** + * A third transfer. Expect an "orphan" failure, since its parent (node11) is deleted + */ + reset(mockedPolicyHandler); + + String errorMsgId = null; + + RetryingTransactionCallback doThirdPrepareCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + tc.transferId = receiver.start("1234", true, receiver.getVersion()); + String snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] { tc.node2 })); + log.debug(snapshot); + receiver.saveSnapshot(tc.transferId, new StringInputStream(snapshot, "UTF-8")); + receiver.saveContent(tc.transferId, tc.node2.getUuid(), new ByteArrayInputStream(dummyContentBytes)); + + return null; + } + }; + + + RetryingTransactionCallback doCommitExpectingFailCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + try + { + receiver.commit(tc.transferId); + fail("Expected an exception"); + } + catch (TransferException ex) + { + // Expected + tc.errorMsgId = ex.getMsgId(); + + ArgumentCaptor transferIdCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor createdNodesCaptor = ArgumentCaptor.forClass(Set.class); + ArgumentCaptor updatedNodesCaptor = ArgumentCaptor.forClass(Set.class); + ArgumentCaptor deletedNodesCaptor = ArgumentCaptor.forClass(Set.class); + + verify(mockedPolicyHandler, times(1)).onEndInboundTransfer(transferIdCaptor.capture(), + createdNodesCaptor.capture(), updatedNodesCaptor.capture(), deletedNodesCaptor.capture()); + + assertEquals(tc.transferId, transferIdCaptor.getValue()); + assertTrue(createdNodesCaptor.getValue().isEmpty()); + assertTrue(updatedNodesCaptor.getValue().isEmpty()); + assertTrue(deletedNodesCaptor.getValue().isEmpty()); + } + + + return null; + } + }; + + RetryingTransactionCallback validateThirdCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + TransferProgress progress = receiver.getProgressMonitor().getProgress(tc.transferId); + assertEquals(TransferProgress.Status.ERROR, progress.getStatus()); + log.debug("Progress indication: " + progress.getCurrentPosition() + "/" + progress.getEndPosition()); + assertNotNull("Progress error", progress.getError()); + assertTrue(progress.getError() instanceof Exception); + assertTrue(tc.errorMsgId, tc.errorMsgId.contains("orphan")); + return null; + } + }; + + try + { + tran.doInTransaction(doThirdPrepareCB, false, true); + tran.doInTransaction(doCommitExpectingFailCB, false, true); + } + finally + { + if(tc.transferId != null) + { + tran.doInTransaction(doEndCB, false, true); + } + } + + tran.doInTransaction(validateThirdCB, false, true); + + log.debug("start testNodeDeleteAndRestore"); + } /** @@ -808,115 +1084,206 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest */ public void testJira_ALF_2772() throws Exception { - setDefaultRollback(true); - startNewTransaction(); - String transferId = receiver.start("1234", true, receiver.getVersion()); - - TransferManifestNormalNode node1 = createContentNode(transferId); - TransferManifestNormalNode node2 = createContentNode(transferId); - TransferManifestNormalNode node11 = createFolderNode(transferId); - - associatePeers(node1, node2); - moveNode(node2, node11); - - TransferManifestDeletedNode deletedNode11 = createDeletedNode(node11); - - endTransaction(); - - List nodes = new ArrayList(); + log.debug("start testJira_ALF_2772"); + final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); + class TestContext + { + TransferManifestNormalNode node1 = null; + TransferManifestNormalNode node2 = null; + TransferManifestNormalNode node11 = null; + TransferManifestDeletedNode deletedNode11 = null; + String transferId = null; + }; - //First we'll just send a folder node - nodes.add(node11); + RetryingTransactionCallback setupCB = new RetryingTransactionCallback() + { + @Override + public TestContext execute() throws Throwable + { + TestContext tc = new TestContext(); + + tc.node1 = createContentNode(); + tc.node2 = createContentNode(); + tc.node11 = createFolderNode(); + + associatePeers(tc.node1, tc.node2); + moveNode(tc.node2, tc.node11); + + tc.deletedNode11 = createDeletedNode(tc.node11); + + return tc; + } + }; - this.setDefaultRollback(false); - startNewTransaction(); + final TestContext tc = tran.doInTransaction(setupCB, false, true); + + RetryingTransactionCallback doEndCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + // Needs to move elsewhere to allow other tests to pass. + receiver.end(tc.transferId); + return null; + } + }; + + + RetryingTransactionCallback doFirstCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + tc.transferId = receiver.start("1234", true, receiver.getVersion()); + + List nodes = new ArrayList(); + + //First we'll just send a folder node + nodes.add(tc.node11); + + String snapshot = createSnapshot(nodes); + log.debug(snapshot); + receiver.saveSnapshot(tc.transferId, new StringInputStream(snapshot, "UTF-8")); + + for (TransferManifestNode node : nodes) + { + receiver.saveContent(tc.transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes)); + } + receiver.commit(tc.transferId); + + for (TransferManifestNode node : nodes) + { + assertTrue(nodeService.exists(node.getNodeRef())); + } + + return null; + } + }; + + /** + * First we'll just send a folder node + */ try { - String snapshot = createSnapshot(nodes); - log.debug(snapshot); - receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8")); - - for (TransferManifestNode node : nodes) + tran.doInTransaction(doFirstCB, false, true); + } + finally + { + if(tc.transferId != null) { - receiver.saveContent(transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes)); - } - receiver.commit(transferId); - - for (TransferManifestNode node : nodes) - { - assertTrue(nodeService.exists(node.getNodeRef())); + tran.doInTransaction(doEndCB, false, true); } } - finally + + + + RetryingTransactionCallback doSecondCB = new RetryingTransactionCallback() { - receiver.end(transferId); - endTransaction(); - } + @Override + public Void execute() throws Throwable + { + tc.transferId = receiver.start("1234", true, receiver.getVersion()); + String snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] { tc.deletedNode11 })); + log.debug(snapshot); + receiver.saveSnapshot(tc.transferId, new StringInputStream(snapshot, "UTF-8")); + receiver.commit(tc.transferId); + + return null; + } + }; + + RetryingTransactionCallback doValidateSecondCB = new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + TransferProgress progress = receiver.getProgressMonitor().getProgress(tc.transferId); + assertEquals(TransferProgress.Status.COMPLETE, progress.getStatus()); - //Now we delete the folder - startNewTransaction(); + NodeRef archivedNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, tc.deletedNode11.getNodeRef().getId()); + assertTrue(nodeService.exists(archivedNodeRef)); + assertTrue(nodeService.hasAspect(archivedNodeRef, ContentModel.ASPECT_ARCHIVED)); + log.debug("Successfully tested existence of archive node: " + tc.deletedNode11.getNodeRef()); + + log.debug("Successfully tested existence of all archive nodes"); + + log.debug("Testing existence of original node: " + tc.node11.getNodeRef()); + assertFalse(nodeService.exists(tc.node11.getNodeRef())); + + log.debug("Successfully tested non-existence of all original nodes"); + + log.debug("Progress indication: " + progress.getCurrentPosition() + "/" + progress.getEndPosition()); + + return null; + } + }; + + /** + * Then delete a folder node + */ try { - transferId = receiver.start("1234", true, receiver.getVersion()); - String snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] { deletedNode11 })); - log.debug(snapshot); - receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8")); - receiver.commit(transferId); + tran.doInTransaction(doSecondCB, false, true); + tran.doInTransaction(doValidateSecondCB, false, true); } finally { - receiver.end(transferId); - endTransaction(); + if(tc.transferId != null) + { + tran.doInTransaction(doEndCB, false, true); + } } + - startNewTransaction(); + /** + * Finally we transfer node2 and node11 (in that order) + */ + RetryingTransactionCallback doThirdCB = new RetryingTransactionCallback() + { + + @Override + public Void execute() throws Throwable + { + + tc.transferId = receiver.start("1234", true, receiver.getVersion()); + String snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] { tc.node2, tc.node11 })); + log.debug(snapshot); + receiver.saveSnapshot(tc.transferId, new StringInputStream(snapshot, "UTF-8")); + receiver.saveContent(tc.transferId, tc.node2.getUuid(), new ByteArrayInputStream(dummyContentBytes)); + receiver.commit(tc.transferId); + + return null; + } + }; + + RetryingTransactionCallback doValidateThirdCB = new RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + + return null; + } + }; + + /** + * Then delete a folder node + */ try { - log.debug("Test success of transfer..."); - TransferProgress progress = receiver.getProgressMonitor().getProgress(transferId); - assertEquals(TransferProgress.Status.COMPLETE, progress.getStatus()); - - NodeRef archivedNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, deletedNode11.getNodeRef().getId()); - assertTrue(nodeService.exists(archivedNodeRef)); - assertTrue(nodeService.hasAspect(archivedNodeRef, ContentModel.ASPECT_ARCHIVED)); - log.debug("Successfully tested existence of archive node: " + deletedNode11.getNodeRef()); - - log.debug("Successfully tested existence of all archive nodes"); - - log.debug("Testing existence of original node: " + node11.getNodeRef()); - assertFalse(nodeService.exists(node11.getNodeRef())); - - log.debug("Successfully tested non-existence of all original nodes"); - - log.debug("Progress indication: " + progress.getCurrentPosition() + "/" + progress.getEndPosition()); + tran.doInTransaction(doThirdCB, false, true); + tran.doInTransaction(doValidateThirdCB, false, true); } finally { - endTransaction(); - } - - - //Finally we transfer node2 and node11 (in that order) - startNewTransaction(); - try - { - transferId = receiver.start("1234", true, receiver.getVersion()); - String snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] { node2, node11 })); - log.debug(snapshot); - receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8")); - receiver.saveContent(transferId, node2.getUuid(), new ByteArrayInputStream(dummyContentBytes)); - receiver.commit(transferId); - } - catch (Exception ex) - { - fail("Test of ALF-2772 failed: " + ex.getMessage()); - } - finally - { - receiver.end(transferId); - endTransaction(); + if(tc.transferId != null) + { + tran.doInTransaction(doEndCB, false, true); + } } } @@ -924,9 +1291,10 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest public void testAsyncCommit() throws Exception { - log.info("testAsyncCommit"); + log.info("start testAsyncCommit"); this.setDefaultRollback(false); + final RetryingTransactionHelper tran = transactionService.getRetryingTransactionHelper(); startNewTransaction(); final String transferId = receiver.start("1234", true, receiver.getVersion()); @@ -934,29 +1302,29 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest startNewTransaction(); final List nodes = new ArrayList(); - final TransferManifestNormalNode node1 = createContentNode(transferId); + final TransferManifestNormalNode node1 = createContentNode(); nodes.add(node1); - final TransferManifestNormalNode node2 = createContentNode(transferId); + final TransferManifestNormalNode node2 = createContentNode(); nodes.add(node2); - TransferManifestNode node3 = createContentNode(transferId); + TransferManifestNode node3 = createContentNode(); nodes.add(node3); - TransferManifestNode node4 = createContentNode(transferId); + TransferManifestNode node4 = createContentNode(); nodes.add(node4); - TransferManifestNode node5 = createContentNode(transferId); + TransferManifestNode node5 = createContentNode(); nodes.add(node5); - TransferManifestNode node6 = createContentNode(transferId); + TransferManifestNode node6 = createContentNode(); nodes.add(node6); - TransferManifestNode node7 = createContentNode(transferId); + TransferManifestNode node7 = createContentNode(); nodes.add(node7); - TransferManifestNode node8 = createFolderNode(transferId); + TransferManifestNode node8 = createFolderNode(); nodes.add(node8); - TransferManifestNode node9 = createFolderNode(transferId); + TransferManifestNode node9 = createFolderNode(); nodes.add(node9); - TransferManifestNode node10 = createFolderNode(transferId); + TransferManifestNode node10 = createFolderNode(); nodes.add(node10); - TransferManifestNormalNode node11 = createFolderNode(transferId); + TransferManifestNormalNode node11 = createFolderNode(); nodes.add(node11); - TransferManifestNode node12 = createFolderNode(transferId); + TransferManifestNode node12 = createFolderNode(); nodes.add(node12); associatePeers(node1, node2); @@ -1110,7 +1478,7 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest /** * @return */ - private TransferManifestNormalNode createContentNode(String transferId) throws Exception + private TransferManifestNormalNode createContentNode(/*String transferId*/) throws Exception { TransferManifestNormalNode node = new TransferManifestNormalNode(); String uuid = GUID.generate(); @@ -1146,7 +1514,7 @@ public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest return node; } - private TransferManifestNormalNode createFolderNode(String transferId) throws Exception + private TransferManifestNormalNode createFolderNode(/*String transferId*/) throws Exception { TransferManifestNormalNode node = new TransferManifestNormalNode(); String uuid = GUID.generate(); diff --git a/source/java/org/alfresco/repo/version/VersionableAspect.java b/source/java/org/alfresco/repo/version/VersionableAspect.java index 95ad61cf10..3d3551bb2a 100644 --- a/source/java/org/alfresco/repo/version/VersionableAspect.java +++ b/source/java/org/alfresco/repo/version/VersionableAspect.java @@ -453,7 +453,7 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate Map after) { if ((this.nodeService.exists(nodeRef) == true) && - !LockUtils.isLockedOrReadOnly(nodeRef, lockService) && + !LockUtils.isLockedAndReadOnly(nodeRef, lockService) && (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE) == true) && (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY) == false)) { diff --git a/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java b/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java index 3270727d7a..be00b81c2c 100644 --- a/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java +++ b/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java @@ -26,16 +26,15 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.HashMap; import java.util.List; +import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.VersionDoesNotExistException; import org.alfresco.service.cmr.version.VersionHistory; import org.alfresco.service.cmr.version.VersionServiceException; import org.alfresco.util.EqualsHelper; -import org.alfresco.util.VersionNumber; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -242,22 +241,25 @@ public class VersionHistoryImpl implements VersionHistory public int compare(Version v1, Version v2) { - Date v1Date = v1.getFrozenModifiedDate(); - Date v2Date = v2.getFrozenModifiedDate(); int result = 0; - if ((v1Date != null) && (v2Date != null)) + + if ((null != v1) && (null != v2)) { - result = v2.getFrozenModifiedDate().compareTo(v1.getFrozenModifiedDate()); - } - else - { - logger.warn("Missing frozen modified date"); - } - - if (result == 0) - { - result = new VersionNumber(v2.getVersionLabel()).compareTo(new VersionNumber(v1.getVersionLabel())); + Serializable dbIdV1 = (null != v1.getVersionProperties()) ? (v1.getVersionProperties().get(ContentModel.PROP_NODE_DBID.getLocalName())) : (null); + Serializable dbIdV2 = (null != v2.getVersionProperties()) ? (v2.getVersionProperties().get(ContentModel.PROP_NODE_DBID.getLocalName())) : (null); + + if ((null != dbIdV1) && (null != dbIdV2)) + { + Long id1 = (dbIdV1 instanceof Integer) ? ((Integer) dbIdV1) : ((Long) dbIdV1); + Long id2 = (dbIdV2 instanceof Integer) ? ((Integer) dbIdV2) : ((Long) dbIdV2); + result = (id2).compareTo(id1); + } + else + { + logger.warn("DB Id of versioned node is missing!"); + } } + return result; } } @@ -273,22 +275,25 @@ public class VersionHistoryImpl implements VersionHistory public int compare(Version v1, Version v2) { - Date v1Date = v1.getFrozenModifiedDate(); - Date v2Date = v2.getFrozenModifiedDate(); int result = 0; - if ((v1Date != null) && (v2Date != null)) + + if ((null != v1) && (null != v2)) { - result = v1.getFrozenModifiedDate().compareTo(v2.getFrozenModifiedDate()); - } - else - { - logger.warn("Missing frozen modified date"); - } - - if (result == 0) - { - result = new VersionNumber(v1.getVersionLabel()).compareTo(new VersionNumber(v2.getVersionLabel())); + Serializable dbIdV1 = (null != v1.getVersionProperties()) ? (v1.getVersionProperties().get(ContentModel.PROP_NODE_DBID.getLocalName())) : (null); + Serializable dbIdV2 = (null != v2.getVersionProperties()) ? (v2.getVersionProperties().get(ContentModel.PROP_NODE_DBID.getLocalName())) : (null); + + if ((null != dbIdV1) && (null != dbIdV2)) + { + Long id1 = (dbIdV1 instanceof Integer) ? ((Integer) dbIdV1) : ((Long) dbIdV1); + Long id2 = (dbIdV2 instanceof Integer) ? ((Integer) dbIdV2) : ((Long) dbIdV2); + result = (id1).compareTo(id2); + } + else + { + logger.warn("DB Id of versioned node is missing!"); + } } + return result; } } diff --git a/source/java/org/alfresco/service/cmr/coci/CheckOutCheckInService.java b/source/java/org/alfresco/service/cmr/coci/CheckOutCheckInService.java index 09ac31db82..d56e81638e 100644 --- a/source/java/org/alfresco/service/cmr/coci/CheckOutCheckInService.java +++ b/source/java/org/alfresco/service/cmr/coci/CheckOutCheckInService.java @@ -81,7 +81,9 @@ public interface CheckOutCheckInService * When a working copy is checked in the current state of the working copy is copied to the * original node. This will include any content updated in the working node. *

- * If version properties are provided the original node will be versioned and updated accordingly. + * If versioning is not enabled on a node (the versionable aspect is not present on the node), the + * check in overwrites the existing node and releases the lock unless the keepCheckedOut flag is used. + * With versioning enabled on the node, a new version is always created. *

* If a content Url is provided it will be used to update the content of the working node before the * checkin operation takes place. diff --git a/source/java/org/alfresco/service/cmr/rule/RuleService.java b/source/java/org/alfresco/service/cmr/rule/RuleService.java index 9fc799112b..526fe6190b 100644 --- a/source/java/org/alfresco/service/cmr/rule/RuleService.java +++ b/source/java/org/alfresco/service/cmr/rule/RuleService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2011 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -77,7 +77,7 @@ public interface RuleService public boolean isEnabled(); /** - * Indicates wether the rules for a given node are enabled or not. If the + * Indicates whether the rules for a given node are enabled or not. If the * rules are not enabled then they will not be executed. * * @param nodeRef the node reference diff --git a/source/java/org/alfresco/util/config/RepositoryFolderConfigBean.java b/source/java/org/alfresco/util/config/RepositoryFolderConfigBean.java index 8f436c30ef..26e37802d3 100644 --- a/source/java/org/alfresco/util/config/RepositoryFolderConfigBean.java +++ b/source/java/org/alfresco/util/config/RepositoryFolderConfigBean.java @@ -18,21 +18,20 @@ */ package org.alfresco.util.config; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.StringTokenizer; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; -import org.alfresco.repo.model.filefolder.FileFolderServiceImpl; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; -import org.alfresco.service.cmr.model.FileNotFoundException; +import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.PropertyCheck; /** @@ -45,45 +44,28 @@ import org.alfresco.util.PropertyCheck; */ public class RepositoryFolderConfigBean extends RepositoryPathConfigBean { - private List folderPath; + private String folderPath; public RepositoryFolderConfigBean() { - folderPath = Collections.emptyList(); + folderPath = ""; } @Override public String toString() { StringBuilder sb = new StringBuilder(128); - sb.append("Folder Path: ").append(super.getStoreRef()).append(super.getRootPath()); - for (String folder : folderPath) - { - sb.append("/").append(folder); - } + sb.append("Folder Path: ").append(super.getStoreRef()).append(super.getRootPath()).append("/").append(folderPath); return sb.toString(); } - /** - * Get the folder name path - */ - public List getFolderNames() - { - return folderPath; - } - /** * * @return Returns the string representation of the folder path */ public String getFolderPath() { - StringBuilder sb = new StringBuilder(56); - for (String pathElement : folderPath) - { - sb.append("/").append(pathElement); - } - return sb.toString(); + return folderPath; } /** @@ -95,10 +77,10 @@ public class RepositoryFolderConfigBean extends RepositoryPathConfigBean { if (!PropertyCheck.isValidPropertyString(folderPath)) { - folderPath = ""; + throw new IllegalArgumentException("Invalid folder name path for property 'folderPath': " + folderPath); } - this.folderPath = new ArrayList(5); StringTokenizer tokenizer = new StringTokenizer(folderPath, "/"); + StringBuilder pathBuff = new StringBuilder(folderPath.length()); while (tokenizer.hasMoreTokens()) { String folderName = tokenizer.nextToken(); @@ -106,8 +88,13 @@ public class RepositoryFolderConfigBean extends RepositoryPathConfigBean { throw new IllegalArgumentException("Invalid folder name path for property 'folderPath': " + folderPath); } - this.folderPath.add(folderName); + pathBuff.append(folderName); + if (tokenizer.hasMoreTokens()) + { + pathBuff.append('/'); + } } + this.folderPath = pathBuff.toString(); } /** @@ -133,24 +120,26 @@ public class RepositoryFolderConfigBean extends RepositoryPathConfigBean " Base path: " + getRootPath()); } // Just choose the root path if the folder path is empty - if (folderPath.size() == 0) + if (folderPath.length() == 0) { return pathStartNodeRef; } else { - try + List nodeRefs = searchService.selectNodes(pathStartNodeRef, folderPath, null, namespaceService, true); + if (nodeRefs.size() == 0) { - FileInfo folderInfo = fileFolderService.resolveNamePath(pathStartNodeRef, folderPath); + throw new AlfrescoRuntimeException("Folder not found: " + this); + } + else + { + NodeRef nodeRef = nodeRefs.get(0); + FileInfo folderInfo = fileFolderService.getFileInfo(nodeRef); if (!folderInfo.isFolder()) { throw new AlfrescoRuntimeException("Not a folder: " + this); } - return folderInfo.getNodeRef(); - } - catch (FileNotFoundException e) - { - throw new AlfrescoRuntimeException("Folder not found: " + this); + return nodeRef; } } // Done @@ -179,18 +168,28 @@ public class RepositoryFolderConfigBean extends RepositoryPathConfigBean " Base path: " + getRootPath()); } // Just choose the root path if the folder path is empty - if (folderPath.size() == 0) + if (folderPath.length() == 0) { return pathStartNodeRef; } else { - FileInfo folderInfo = FileFolderServiceImpl.makeFolders( - fileFolderService, - pathStartNodeRef, - folderPath, - ContentModel.TYPE_FOLDER); - return folderInfo.getNodeRef(); + StringTokenizer folders = new StringTokenizer(folderPath, "/"); + NodeRef nodeRef = pathStartNodeRef; + while (folders.hasMoreTokens()) + { + QName folderQName = QName.createQName(folders.nextToken(), namespaceService); + List children = nodeService.getChildAssocs(nodeRef, RegexQNamePattern.MATCH_ALL, folderQName); + if (children.isEmpty()) + { + nodeRef = fileFolderService.create(nodeRef, folderQName.getLocalName(), ContentModel.TYPE_FOLDER, folderQName).getNodeRef(); + } + else + { + nodeRef = children.get(0).getChildRef(); + } + } + return nodeRef; } // Done }