diff --git a/config/alfresco/auditConfig.xml b/config/alfresco/auditConfig.xml
index f2e43fbb38..e68bef07ee 100644
--- a/config/alfresco/auditConfig.xml
+++ b/config/alfresco/auditConfig.xml
@@ -38,7 +38,9 @@
-
+
+
+
@@ -46,14 +48,18 @@
-
+
+
+
+
+
-
+
@@ -65,7 +71,7 @@
-
+
@@ -90,11 +96,13 @@
-
+
-
+
+
+
-
+
@@ -178,4 +186,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml
index d594977215..2d6444b057 100644
--- a/config/alfresco/bootstrap-context.xml
+++ b/config/alfresco/bootstrap-context.xml
@@ -153,6 +153,35 @@
+
+
+
+
+ jbpm
+ alfresco/workflow/review_processdefinition.xml
+ text/xml
+ true
+
+
+ jbpm
+ alfresco/workflow/adhoc_processdefinition.xml
+ text/xml
+ true
+
+
+
+
+
+ alfresco/workflow/workflowModel.xml
+
+
+
+
+ alfresco/workflow/workflow-messages
+
+
+
+
diff --git a/config/alfresco/bootstrap/system.xml b/config/alfresco/bootstrap/system.xml
index a868e910c7..501fc4324d 100644
--- a/config/alfresco/bootstrap/system.xml
+++ b/config/alfresco/bootstrap/system.xml
@@ -42,7 +42,7 @@
-
+
diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml
index e444cf8ef4..46f76c6af6 100644
--- a/config/alfresco/core-services-context.xml
+++ b/config/alfresco/core-services-context.xml
@@ -404,13 +404,14 @@
-
+
alfresco/model/dictionaryModel.xmlalfresco/model/systemModel.xmlalfresco/model/contentModel.xml
+ alfresco/model/bpmModel.xmlalfresco/model/applicationModel.xmlalfresco/model/forumModel.xmlalfresco/model/recordsModel.xml
@@ -428,6 +429,7 @@
alfresco/messages/system-modelalfresco/messages/dictionary-modelalfresco/messages/content-model
+ alfresco/messages/bpm-messagesalfresco/messages/application-modelalfresco/messages/forum-model
diff --git a/config/alfresco/extension/ldap-authentication-context.xml.sample b/config/alfresco/extension/ldap-authentication-context.xml.sample
index 34dbe20833..d0259eb5d7 100644
--- a/config/alfresco/extension/ldap-authentication-context.xml.sample
+++ b/config/alfresco/extension/ldap-authentication-context.xml.sample
@@ -3,24 +3,14 @@
-
+
-
-
- org.alfresco.repo.security.authentication.MutableAuthenticationDao
+
+
+ true
-
-
-
-
-
-
-
-
- ${server.transaction.mode.default}
-
-
-
+
+
@@ -317,9 +307,9 @@
-
+
- 30000
+ 300000
@@ -347,9 +337,9 @@
-
+
- 30000
+ 300000
diff --git a/config/alfresco/messages/bpm-messages.properties b/config/alfresco/messages/bpm-messages.properties
index 8a8886cb2d..48803513dd 100644
--- a/config/alfresco/messages/bpm-messages.properties
+++ b/config/alfresco/messages/bpm-messages.properties
@@ -4,8 +4,8 @@ bpm_businessprocessmodel.title=Business Process Model
bpm_businessprocessmodel.description=Base definitions of all Business Processes
# Default transition
-bpm_businessprocessmodel.transition.title=Done
-bpm_businessprocessmodel.transition.description=Done
+bpm_businessprocessmodel.transition.title=Task Done
+bpm_businessprocessmodel.transition.description=Task Done
# Base Task
bpm_businessprocessmodel.type.bpm_task.title=Task
@@ -36,6 +36,8 @@ bpm_businessprocessmodel.property.bpm_workflowInstanceId.title=Workflow Instance
bpm_businessprocessmodel.property.bpm_workflowInstanceId.description=Workflow Instance Id
bpm_businessprocessmodel.property.bpm_context.title=Task Context
bpm_businessprocessmodel.property.bpm_context.description=The context within which this task has been assigned
+bpm_businessprocessmodel.property.bpm_description.title=Task Description
+bpm_businessprocessmodel.property.bpm_description.description=Description of what needs to be achieved
bpm_businessprocessmodel.property.bpm_outcome.title=Task Outcome
bpm_businessprocessmodel.property.bpm_outcome.description=Decision made on completing Task
bpm_businessprocessmodel.property.bpm_completedItems.title=Completed Items
@@ -48,3 +50,15 @@ bpm_businessprocessmodel.association.bpm_package.title=Content Package
bpm_businessprocessmodel.association.bpm_package.description=The collection of content routed through the workflow
bpm_businessprocessmodel.aspect.bpm_workflowPackage.title=Workflow Package
bpm_businessprocessmodel.aspect.bpm_workflowPackage.description=The collection of content routed through the workflow
+
+# Workflow Start Task
+bpm_businessprocessmodel.type.bpm_startTask.title=Workflow Start Task
+bpm_businessprocessmodel.type.bpm_startTask.description=Task used to collect information required for initiating Workflow
+bpm_businessprocessmodel.property.bpm_workflowDescription.title=Description
+bpm_businessprocessmodel.property.bpm_workflowDescription.description=Description
+bpm_businessprocessmodel.property.bpm_workflowDueDate.title=Workflow Due Date
+bpm_businessprocessmodel.property.bpm_workflowDueDate.description=Workflow Due Date
+bpm_businessprocessmodel.property.bpm_workflowPriority.title=Workflow Priority
+bpm_businessprocessmodel.property.bpm_workflowPriority.description=Workflow Priority
+bpm_businessprocessmodel.association.bpm_assignee.title=Workflow Assignee
+bpm_businessprocessmodel.association.bpm_assignee.description=Workflow Assignee
diff --git a/config/alfresco/mimetype/openoffice-document-formats.xml b/config/alfresco/mimetype/openoffice-document-formats.xml
index 1c18b17845..9579d1ba0d 100644
--- a/config/alfresco/mimetype/openoffice-document-formats.xml
+++ b/config/alfresco/mimetype/openoffice-document-formats.xml
@@ -10,6 +10,7 @@
Presentationimpress_pdf_ExportSpreadsheetcalc_pdf_ExportTextwriter_pdf_Export
+ Htmlwriter_web_pdf_Export
@@ -26,7 +27,8 @@
- 1. additional files may be generated for images and this would require extra care in a servlet environment
- 2. output quality does not seem to be very good in many cases
-->
- HTML
+ Html
+ Htmltext/htmlhtml
@@ -44,6 +46,7 @@
odtTextwriter8
+ Htmlwriterweb8_writer
diff --git a/config/alfresco/model/bpmModel.xml b/config/alfresco/model/bpmModel.xml
index 45cd982c46..e4bd07cdb5 100644
--- a/config/alfresco/model/bpmModel.xml
+++ b/config/alfresco/model/bpmModel.xml
@@ -2,269 +2,321 @@
- Business Process Model
- Alfresco
- 1.0
+ Business Process Model
+ Alfresco
+ 1.0
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
- 1
- 2
- 3
-
-
-
-
-
-
-
-
- Not Yet Started
- In Progress
- On Hold
- Cancelled
- Completed
-
-
-
-
-
- 0
- 100
-
-
-
-
-
-
-
-
-
-
-
- Task
- Task
- cm:content
-
-
-
-
-
-
-
-
-
-
-
-
- Task Identifier
- d:long
- true
- true
-
-
-
-
-
-
- Start Date
- d:date
- true
-
-
- End Date
- d:date
- true
-
-
- Due Date
- d:date
-
+
+
+
-
-
-
-
- Status
- d:text
- true
- Not Yet Started
-
-
-
-
-
- Priority
- d:int
- true
- 2
-
-
-
-
-
- Percentage Complete
- d:int
- true
- 0
-
-
-
-
+
-
-
-
-
+
+
+
+
+ 1
+ 2
+ 3
+
+
+
-
+
+
+
+
+ Not Yet Started
+ In Progress
+ On Hold
+ Cancelled
+ Completed
+
+
+
-
+
+
+ 0
+
+
+ 100
+
+
-
-
- Pooled Users
-
- false
- false
-
-
- cm:person
- false
- true
-
-
+
-
+
-
- cm:ownable
-
-
+
+
+
+
+
+ cm:content
+
+
+
+
+
+
+
+
+
+
+
+
+ d:long
+ true
+ true
+
+
+
+
+ d:text
+
+
+
+
+
+
+ d:date
+ true
+
+
+ d:date
+ true
+
+
+ d:date
+
+
+
+
+
+
+ d:text
+ true
+ Not Yet Started
+
+
+
+
+
+ d:int
+ true
+ 2
+
+
+
+
+
+ d:int
+ true
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ false
+
+
+ cm:person
+ false
+ true
+
+
+
+
+
+
+ cm:ownable
+
+
-
-
-
-
-
- Workflow Task
- Task assigned via Workflow
- bpm:task
-
-
+
+
+
-
-
-
- Task Context
- d:noderef
-
-
-
-
- Task Outcome
- d:text
-
+
+ bpm:task
-
-
- d:noderef
- true
-
+
-
-
- d:text
-
+
+
+
+ d:noderef
+
-
-
- d:text
- workflow_item_read_actions
-
-
+
+
+ d:text
+
-
-
-
- Workflow Package
-
- false
- false
-
-
- bpm:workflowPackage
- true
- false
-
-
-
-
-
-
+
+
+ d:noderef
+ true
+
+
+
+
+ d:text
+
+
+
+
+
+ d:text
+ workflow_item_read_actions
+
+
+
+
+
+
+
+
+ false
+ false
+
+
+ bpm:workflowPackage
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+ bpm:workflowTask
+
+
+
+
+
+ d:text
+
+
+
+
+ d:date
+
+
+
+
+ d:int
+ 2
+
+
+
+
+
+
+
+
+
+
+
+ false
+ false
+
+
+ cm:person
+ true
+ false
+
+
+
+
+
+
+
+
+ workflow_collection_actions
+
+
+
+ workflow_item_collection_actions
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
- Workflow Package
-
+
+
+
+
+
+
-
-
-
-
- Workflow Definition Id
- d:text
-
-
- Workflow Definition Name
- d:text
-
-
- Workflow Instance Id
- d:text
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ d:text
+
+
+ d:text
+
+
+ d:text
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
\ No newline at end of file
diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml
index da5560951d..84bd9bbaef 100644
--- a/config/alfresco/model/contentModel.xml
+++ b/config/alfresco/model/contentModel.xml
@@ -49,7 +49,7 @@
false
- false
+ truesys:base
diff --git a/config/alfresco/model/dataTypeAnalyzers.properties b/config/alfresco/model/dataTypeAnalyzers.properties
index 75b6672692..7529f289d2 100644
--- a/config/alfresco/model/dataTypeAnalyzers.properties
+++ b/config/alfresco/model/dataTypeAnalyzers.properties
@@ -1,17 +1,17 @@
# Data Type Index Analyzers
-d_dictionary.datatype.d_any.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer
-d_dictionary.datatype.d_text.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer
-d_dictionary.datatype.d_content.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer
+d_dictionary.datatype.d_any.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser
+d_dictionary.datatype.d_text.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser
+d_dictionary.datatype.d_content.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser
d_dictionary.datatype.d_int.analyzer=org.alfresco.repo.search.impl.lucene.analysis.IntegerAnalyser
d_dictionary.datatype.d_long.analyzer=org.alfresco.repo.search.impl.lucene.analysis.LongAnalyser
d_dictionary.datatype.d_float.analyzer=org.alfresco.repo.search.impl.lucene.analysis.FloatAnalyser
d_dictionary.datatype.d_double.analyzer=org.alfresco.repo.search.impl.lucene.analysis.DoubleAnalyser
d_dictionary.datatype.d_date.analyzer=org.alfresco.repo.search.impl.lucene.analysis.DateAnalyser
d_dictionary.datatype.d_datetime.analyzer=org.alfresco.repo.search.impl.lucene.analysis.DateAnalyser
-d_dictionary.datatype.d_boolean.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer
-d_dictionary.datatype.d_qname.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer
-d_dictionary.datatype.d_guid.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer
-d_dictionary.datatype.d_category.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer
-d_dictionary.datatype.d_noderef.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer
-d_dictionary.datatype.d_path.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer
+d_dictionary.datatype.d_boolean.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser
+d_dictionary.datatype.d_qname.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser
+d_dictionary.datatype.d_guid.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser
+d_dictionary.datatype.d_category.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser
+d_dictionary.datatype.d_noderef.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser
+d_dictionary.datatype.d_path.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser
diff --git a/config/alfresco/model/dictionaryModel.xml b/config/alfresco/model/dictionaryModel.xml
index 95fa5e2b69..2c57afdd57 100644
--- a/config/alfresco/model/dictionaryModel.xml
+++ b/config/alfresco/model/dictionaryModel.xml
@@ -19,17 +19,17 @@
- org.apache.lucene.analysis.standard.StandardAnalyzer
+ org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyserjava.lang.Object
- org.apache.lucene.analysis.standard.StandardAnalyzer
+ org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyserjava.lang.String
- org.apache.lucene.analysis.standard.StandardAnalyzer
+ org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyserorg.alfresco.service.cmr.repository.ContentData
@@ -64,37 +64,37 @@
- org.apache.lucene.analysis.standard.StandardAnalyzer
+ org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyserjava.lang.Boolean
- org.apache.lucene.analysis.standard.StandardAnalyzer
+ org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyserorg.alfresco.service.namespace.QName
- org.apache.lucene.analysis.standard.StandardAnalyzer
+ org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyserorg.alfresco.service.cmr.repository.NodeRef
- org.apache.lucene.analysis.standard.StandardAnalyzer
+ org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyserorg.alfresco.service.cmr.repository.ChildAssociationRef
- org.apache.lucene.analysis.standard.StandardAnalyzer
+ org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyserorg.alfresco.service.cmr.repository.AssociationRef
- org.apache.lucene.analysis.standard.StandardAnalyzer
+ org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyserorg.alfresco.service.cmr.repository.Path
- org.apache.lucene.analysis.standard.StandardAnalyzer
+ org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyserorg.alfresco.service.cmr.repository.NodeRef
diff --git a/config/alfresco/model/permissionDefinitions.xml b/config/alfresco/model/permissionDefinitions.xml
index 85d907b5c3..741ed672d8 100644
--- a/config/alfresco/model/permissionDefinitions.xml
+++ b/config/alfresco/model/permissionDefinitions.xml
@@ -62,11 +62,48 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -80,10 +117,10 @@
-
-
+
+
@@ -93,10 +130,10 @@
-
-
+
+
@@ -106,10 +143,10 @@
-
-
+
+
@@ -124,42 +161,42 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
@@ -167,52 +204,55 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
+
+
-
+
+
-
+
+
@@ -222,17 +262,19 @@
-
+
+
-
+
+
@@ -284,6 +326,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -299,6 +356,7 @@
+
@@ -309,16 +367,20 @@
-
+
+
+
+
+
-
-
+
+
-
+
@@ -334,24 +396,34 @@
-
+
+
+
-
+
+
+
-
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
+
+
diff --git a/config/alfresco/model/workflowModel.xml b/config/alfresco/model/workflowModel.xml
deleted file mode 100644
index 0185344dee..0000000000
--- a/config/alfresco/model/workflowModel.xml
+++ /dev/null
@@ -1,160 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Submit Review Task
- bpm:workflowTask
-
-
-
-
- Review Due Date
- d:date
-
-
-
- Review Priority
- d:int
- 2
-
-
-
-
-
-
-
-
-
-
- Reviewer
-
- false
- false
-
-
- cm:person
- true
- false
-
-
-
-
-
-
-
-
- workflow_collection_actions
-
-
-
- workflow_item_collection_actions
-
-
-
-
-
-
-
-
- Review Task
- bpm:workflowTask
-
-
-
-
- workflow_item_edit_actions
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- bpm:workflowTask
-
-
-
- Description
- d:text
-
-
-
-
-
- Submit Adhoc Task
- wf:baseAdhocTask
-
-
-
- Due Date
- d:date
-
-
-
- Priority
- d:int
- 2
-
-
-
-
-
-
- Email Notification
- d:boolean
-
-
-
-
-
- Assignee
-
- false
- false
-
-
- cm:person
- true
- false
-
-
-
-
-
-
- Adhoc Task
- wf:baseAdhocTask
-
-
-
- Completed Adhoc Task
- wf:baseAdhocTask
-
-
-
-
-
\ No newline at end of file
diff --git a/config/alfresco/node-services-context.xml b/config/alfresco/node-services-context.xml
index d1c98514ea..7a4a7a5f1e 100644
--- a/config/alfresco/node-services-context.xml
+++ b/config/alfresco/node-services-context.xml
@@ -86,7 +86,7 @@
false
- false
+ true5
diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties
index 87530803c5..681bec09e2 100644
--- a/config/alfresco/version.properties
+++ b/config/alfresco/version.properties
@@ -7,7 +7,7 @@
version.major=1
version.minor=4
version.revision=0
-version.label=Preview
+version.label=RC1
# Edition label
diff --git a/config/alfresco/workflow-context.xml b/config/alfresco/workflow-context.xml
index 097521554a..468f5d350a 100644
--- a/config/alfresco/workflow-context.xml
+++ b/config/alfresco/workflow-context.xml
@@ -3,44 +3,6 @@
-
-
-
-
-
-
-
-
- jbpm
- org/alfresco/repo/workflow/jbpm/review_and_approve_processdefinition.xml
- text/xml
- false
-
-
- jbpm
- org/alfresco/repo/workflow/jbpm/adhoc_task_processdefinition.xml
- text/xml
- false
-
-
-
-
-
-
-
-
- alfresco/model/bpmModel.xml
- alfresco/model/workflowModel.xml
-
-
-
-
- alfresco/messages/bpm-messages
- alfresco/messages/workflow-messages
-
-
-
-
@@ -49,6 +11,7 @@
+
@@ -58,7 +21,6 @@
-
@@ -70,7 +32,7 @@
- false
+ true
@@ -103,7 +65,7 @@
-
+
diff --git a/config/alfresco/workflow/adhoc_processdefinition.xml b/config/alfresco/workflow/adhoc_processdefinition.xml
new file mode 100644
index 0000000000..10f7f7038a
--- /dev/null
+++ b/config/alfresco/workflow/adhoc_processdefinition.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/workflow/review_processdefinition.xml b/config/alfresco/workflow/review_processdefinition.xml
new file mode 100644
index 0000000000..049a9b459d
--- /dev/null
+++ b/config/alfresco/workflow/review_processdefinition.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/messages/workflow-messages.properties b/config/alfresco/workflow/workflow-messages.properties
similarity index 71%
rename from config/alfresco/messages/workflow-messages.properties
rename to config/alfresco/workflow/workflow-messages.properties
index c6053ad28e..8a93442cef 100644
--- a/config/alfresco/messages/workflow-messages.properties
+++ b/config/alfresco/workflow/workflow-messages.properties
@@ -11,13 +11,6 @@ wf_review.workflow.description=Review & approval of content
wf_workflowmodel.type.wf_submitReviewTask.title=Submit Review
wf_workflowmodel.type.wf_submitReviewTask.description=Submit documents for review & approval
-wf_workflowmodel.property.wf_reviewDueDate.title=Review Due Date
-wf_workflowmodel.property.wf_reviewDueDate.description=Review Due Date
-wf_workflowmodel.property.wf_reviewPriority.title=Review Priority
-wf_workflowmodel.property.wf_reviewPriority.description=Review Priority
-wf_workflowmodel.association.wf_reviewer.title=Reviewer
-wf_workflowmodel.association.wf_reviewer.description=Reviewer
-
wf_workflowmodel.type.wf_reviewTask.title=Review
wf_workflowmodel.type.wf_reviewTask.description=Review Documents to Approve or Reject them
@@ -42,7 +35,6 @@ wf_review.task.wf_approvedTask.description=Approved
wf_review.node.end.title=End
wf_review.node.end.description=End
-
#
# Adhoc Task Workflow
#
@@ -54,14 +46,8 @@ wf_adhoc.workflow.description=Assign task to colleague
wf_workflowmodel.type.wf_submitAdhocTask.title=Submit Adhoc Task
wf_workflowmodel.type.wf_submitAdhocTask.description=Allocate task to colleague
-wf_workflowmodel.property.wf_adhocDescription.title=Task Description
-wf_workflowmodel.property.wf_adhocDescription.description=Description of what needs to be achieved
-wf_workflowmodel.property.wf_adhocDueDate.description=Task Due Date
-wf_workflowmodel.property.wf_adhocPriority.title=Task Priority
wf_workflowmodel.property.wf_notifyMe.title=Notify Me
wf_workflowmodel.property.wf_notifyMe.description=Notify me when task is complete
-wf_workflowmodel.association.wf_assignee.title=Assignee
-wf_workflowmodel.association.wf_assignee.description=Who's doing the task
wf_workflowmodel.type.wf_adhocTask.title=Adhoc Task
wf_workflowmodel.type.wf_adhocTask.description=Adhoc Task allocated by colleague
wf_workflowmodel.type.wf_completedAdhocTask.title=Adhoc Task Completed
diff --git a/config/alfresco/workflow/workflowModel.xml b/config/alfresco/workflow/workflowModel.xml
new file mode 100644
index 0000000000..73fdd9e553
--- /dev/null
+++ b/config/alfresco/workflow/workflowModel.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ bpm:startTask
+
+
+
+ bpm:workflowTask
+
+
+
+
+ workflow_item_edit_actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+ bpm:startTask
+
+
+
+ d:boolean
+ false
+
+
+
+
+
+
+ bpm:workflowTask
+
+
+
+ bpm:workflowTask
+
+
+
+
+
\ No newline at end of file
diff --git a/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java
index 0b973efc20..c5647faff4 100644
--- a/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java
+++ b/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java
@@ -608,10 +608,28 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticator implements Ca
// Process the security blob
byte[] respBlob = null;
-
+ boolean isNTLMSSP = false;
+
try
{
- if ( useRawNTLMSSP())
+
+ // Check if the blob has the NTLMSSP signature
+
+ if ( secBlobLen >= NTLM.Signature.length) {
+
+ // Check for the NTLMSSP signature
+
+ int idx = 0;
+ while ( idx < NTLM.Signature.length && buf[secBlobPos + idx] == NTLM.Signature[ idx])
+ idx++;
+
+ if ( idx == NTLM.Signature.length)
+ isNTLMSSP = true;
+ }
+
+ // Process the security blob
+
+ if ( isNTLMSSP == true)
{
// Process an NTLMSSP security blob
@@ -657,7 +675,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticator implements Ca
// Check if there is/was a session setup object stored in the session, this indicates a multi-stage session
// setup so set the status code accordingly
- if ( useRawNTLMSSP() || sess.hasSetupObject() || setupObj != null)
+ if ( useRawNTLMSSP() || isNTLMSSP == true || sess.hasSetupObject() || setupObj != null)
{
// NTLMSSP has two stages, if there is a stored setup object then indicate more processing
// required
diff --git a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
index 6895b50b97..46c7e16839 100644
--- a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
+++ b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java
@@ -1774,7 +1774,7 @@ public class ServerConfiguration implements ApplicationListener
// Check if the appropriate authentication component type is configured
if ( ntlmMode != NTLMMode.NONE)
- throw new AlfrescoRuntimeException("Wrong authentication setup for passthru authenticator");
+ throw new AlfrescoRuntimeException("Wrong authentication setup for passthru authenticator (can only be used with LDAP/JAAS auth component)");
// Load the passthru authenticator dynamically
diff --git a/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java
index d01bee8699..e598b5d543 100644
--- a/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java
+++ b/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java
@@ -831,20 +831,108 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
}
else
{
- // Create the transaction
-
- sess.beginTransaction(transactionService, true);
-
- // Get the file information to check if the file/folder exists
-
- FileInfo info = getFileInformation(sess, tree, name);
- if (info.isDirectory())
+ // Check if pseudo files are enabled
+
+ if ( hasPseudoFileInterface(ctx))
{
- status = FileStatus.DirectoryExists;
+ // Check if the file name is a pseudo file name
+
+ if ( getPseudoFileInterface( ctx).isPseudoFile(sess, tree, name)) {
+ // Make sure the parent folder has a file state, and the path exists
+
+ String[] paths = FileName.splitPath( name);
+ fstate = ctx.getStateTable().findFileState( paths[0]);
+
+ if ( fstate == null) {
+
+ // Check if the path exists
+
+ if ( fileExists( sess, tree, paths[0]) == FileStatus.DirectoryExists)
+ {
+ // Create the file state
+
+ fstate = ctx.getStateTable().findFileState( paths[0], true, true);
+
+ fstate.setFileStatus( FileStatus.DirectoryExists);
+
+ // Get the node for the folder path
+
+ sess.beginTransaction(transactionService, true);
+ fstate.setNodeRef( getNodeForPath( tree, paths[0]));
+
+ // Add pseudo files to the folder
+
+ getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
+
+ // Debug
+
+ if ( logger.isInfoEnabled())
+ logger.info( "Added file state for pseudo files folder (exists) - " + paths[0]);
+ }
+ }
+ else if ( fstate.hasPseudoFiles() == false)
+ {
+ // Make sure the file state has the node ref
+
+ if ( fstate.hasNodeRef() == false)
+ {
+ // Create the transaction
+
+ sess.beginTransaction(transactionService, true);
+
+ // Get the node for the folder path
+
+ fstate.setNodeRef( getNodeForPath( tree, paths[0]));
+ }
+
+ // Add pseudo files for the parent folder
+
+ getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
+
+ // Debug
+
+ if ( logger.isInfoEnabled())
+ logger.info( "Added pseudo files for folder (exists) - " + paths[0]);
+ }
+
+ // Check if the path is to a pseudo file
+
+ PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, name);
+ if ( pfile != null)
+ {
+ // Indicate that the file exists
+
+ status = FileStatus.FileExists;
+ }
+ else
+ {
+ // Failed to find pseudo file
+
+ if ( logger.isInfoEnabled())
+ logger.info( "Failed to find pseudo file (exists) - " + name);
+ }
+ }
}
- else
+
+ // If the file is not a pseudo file then search for the file
+
+ if ( status == FileStatus.Unknown)
{
- status = FileStatus.FileExists;
+ // Create the transaction
+
+ sess.beginTransaction(transactionService, true);
+
+ // Get the file information to check if the file/folder exists
+
+ FileInfo info = getFileInformation(sess, tree, name);
+ if (info.isDirectory())
+ {
+ status = FileStatus.DirectoryExists;
+ }
+ else
+ {
+ status = FileStatus.FileExists;
+ }
}
}
}
@@ -861,13 +949,17 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
status = FileStatus.NotExist;
}
- // done
+ // Debug
+
if (logger.isDebugEnabled())
{
logger.debug("File status determined: \n" +
" name: " + name + "\n" +
" status: " + status);
}
+
+ // Return the file/folder status
+
return status;
}
@@ -896,15 +988,65 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
if ( hasPseudoFileInterface(ctx))
{
- // Check if the path is to a pseudo file
-
- PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, params.getPath());
- if ( pfile != null)
- {
- // Create a network file to access the pseudo file data
-
- return pfile.getFile( params.getPath());
- }
+ // Check if the file name is a pseudo file name
+
+ String path = params.getPath();
+
+ if ( getPseudoFileInterface( ctx).isPseudoFile(sess, tree, path)) {
+
+ // Make sure the parent folder has a file state, and the path exists
+
+ String[] paths = FileName.splitPath( path);
+ FileState fstate = ctx.getStateTable().findFileState( paths[0]);
+
+ if ( fstate == null) {
+
+ // Check if the path exists
+
+ if ( fileExists( sess, tree, paths[0]) == FileStatus.DirectoryExists)
+ {
+ // Create the file state and add any pseudo files
+
+ fstate = ctx.getStateTable().findFileState( paths[0], true, true);
+
+ fstate.setFileStatus( FileStatus.DirectoryExists);
+ getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
+
+ // Debug
+
+ if ( logger.isInfoEnabled())
+ logger.info( "Added file state for pseudo files folder (open) - " + paths[0]);
+ }
+ }
+ else if ( fstate.hasPseudoFiles() == false)
+ {
+ // Add pseudo files for the parent folder
+
+ getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
+
+ // Debug
+
+ if ( logger.isInfoEnabled())
+ logger.info( "Added pseudo files for folder (open) - " + paths[0]);
+ }
+
+ // Check if the path is to a pseudo file
+
+ PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, params.getPath());
+ if ( pfile != null)
+ {
+ // Create a network file to access the pseudo file data
+
+ return pfile.getFile( params.getPath());
+ }
+ else
+ {
+ // Failed to find pseudo file
+
+ if ( logger.isInfoEnabled())
+ logger.info( "Failed to find pseudo file (open) - " + params.getPath());
+ }
+ }
}
// Not a pseudo file, try and open a normal file/folder node
@@ -1045,7 +1187,7 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
try
{
- // get the device root
+ // Get the device root
ContentContext ctx = (ContentContext) tree.getContext();
NodeRef deviceRootNodeRef = ctx.getRootNode();
@@ -1888,7 +2030,8 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
FileState fstate = ctx.getStateTable().findFileState(path);
if ( fstate != null && fstate.hasNodeRef() && fstate.exists() )
{
- // check that the node exists
+ // Check that the node exists
+
if (nodeService.exists(fstate.getNodeRef()))
{
// Bump the file states expiry time
diff --git a/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java b/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java
index fe39a6b277..5f2651b1b4 100644
--- a/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java
+++ b/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java
@@ -16,6 +16,10 @@
*/
package org.alfresco.filesys.smb.server.repo.desk;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
import org.alfresco.filesys.server.filesys.FileName;
import org.alfresco.filesys.server.filesys.NotifyChange;
import org.alfresco.filesys.smb.server.repo.DesktopAction;
@@ -81,9 +85,10 @@ public class CheckInOutDesktopAction extends DesktopAction {
{
try
{
- // Check in the file
+ // Check in the file, pass an empty version properties so that veriosnable nodes create a new version
- getCheckInOutService().checkin( target.getNode(), null, null, false);
+ Map versionProperties = new HashMap();
+ getCheckInOutService().checkin( target.getNode(), versionProperties, null, false);
// Check if there are any file/directory change notify requests active
diff --git a/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java b/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java
index 24f8e08896..ab38534a88 100644
--- a/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java
+++ b/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java
@@ -68,6 +68,27 @@ public class ContentPseudoFileImpl implements PseudoFileInterface
if ( pfile != null)
isPseudo = true;
}
+ else
+ {
+ // Check if the file name matches a pseudo-file name in the desktop actions list
+
+ if ( ctx.hasDesktopActions())
+ {
+ DesktopActionTable actions = ctx.getDesktopActions();
+ if ( actions.getActionViaPseudoName( paths[1]) != null)
+ isPseudo = true;
+ }
+
+ // Check if the URL file is enabled
+
+ if ( isPseudo == false && ctx.hasURLFile())
+ {
+ // Check if it is the URL file name
+
+ if ( ctx.getURLFileName().equals( paths[1]))
+ isPseudo = true;
+ }
+ }
// Return the pseudo file status
diff --git a/source/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java b/source/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java
index 2a49156dee..1505941515 100644
--- a/source/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java
+++ b/source/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java
@@ -84,6 +84,10 @@ public class ScriptActionExecuter extends ActionExecuterAbstractBase
{
NodeRef scriptRef = (NodeRef)action.getParameterValue(PARAM_SCRIPTREF);
NodeRef spaceRef = this.serviceRegistry.getRuleService().getOwningNodeRef(action);
+ if (spaceRef == null)
+ {
+ spaceRef = nodeService.getPrimaryParent(actionedUponNodeRef).getParentRef();
+ }
if (nodeService.exists(scriptRef))
{
diff --git a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java
index 89c040ca15..28fafbcc91 100644
--- a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java
+++ b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java
@@ -240,7 +240,10 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase
contentWriter.setMimetype(mimeType); // new mimetype
contentWriter.setEncoding(contentReader.getEncoding()); // original encoding
- // Try and transform the content
+ // Try and transform the content - failures are caught and allowed to fail silently.
+ // This is unique to this action, and is essentially a broken pattern.
+ // Clients should rather get the exception and then decide to replay with rules/actions turned off or not.
+ // TODO: Check failure patterns for actions.
try
{
doTransform(ruleAction, contentReader, contentWriter);
@@ -258,8 +261,16 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase
}
}
+ /**
+ * Executed in a new transaction so that failures don't cause the entire transaction to rollback.
+ */
protected void doTransform(Action ruleAction, ContentReader contentReader, ContentWriter contentWriter)
{
+ // try to pre-empt the lack of a transformer
+ if (!this.contentService.isTransformable(contentReader, contentWriter))
+ {
+ throw new NoTransformerException(contentReader.getMimetype(), contentWriter.getMimetype());
+ }
this.contentService.transform(contentReader, contentWriter);
}
diff --git a/source/java/org/alfresco/repo/audit/AuditComponentImpl.java b/source/java/org/alfresco/repo/audit/AuditComponentImpl.java
index 6ee47e0c6d..240bebf881 100644
--- a/source/java/org/alfresco/repo/audit/AuditComponentImpl.java
+++ b/source/java/org/alfresco/repo/audit/AuditComponentImpl.java
@@ -23,6 +23,7 @@ import java.net.UnknownHostException;
import java.util.Date;
import java.util.List;
+import org.alfresco.repo.audit.model.TrueFalseUnset;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.Auditable;
@@ -123,13 +124,26 @@ public class AuditComponentImpl implements AuditComponent
{
if ((auditFlag.get() == null) || (!auditFlag.get().booleanValue()))
{
+ boolean auditInternal = (auditModel.getAuditInternalServiceMethods(mi) == TrueFalseUnset.TRUE);
try
{
- auditFlag.set(Boolean.TRUE);
-
Method method = mi.getMethod();
String methodName = method.getName();
String serviceName = publicServiceIdentifier.getPublicServiceName(mi);
+
+ if (!auditInternal)
+ {
+ auditFlag.set(Boolean.TRUE);
+ }
+ else
+ {
+ if (s_logger.isDebugEnabled())
+ {
+ s_logger.debug("Auditing internal service use for - " + serviceName + "." + methodName);
+ }
+ }
+
+
if (method.isAnnotationPresent(Auditable.class))
{
@@ -170,7 +184,10 @@ public class AuditComponentImpl implements AuditComponent
}
finally
{
- auditFlag.set(Boolean.FALSE);
+ if (!auditInternal)
+ {
+ auditFlag.set(Boolean.FALSE);
+ }
}
}
else
@@ -272,7 +289,7 @@ public class AuditComponentImpl implements AuditComponent
}
else if (returnObject instanceof StoreRef)
{
- auditInfo.setKeyStore((StoreRef)returnObject);
+ auditInfo.setKeyStore((StoreRef) returnObject);
}
}
}
diff --git a/source/java/org/alfresco/repo/audit/MethodAuditModel.java b/source/java/org/alfresco/repo/audit/MethodAuditModel.java
index 37b1200173..62791ca5e6 100644
--- a/source/java/org/alfresco/repo/audit/MethodAuditModel.java
+++ b/source/java/org/alfresco/repo/audit/MethodAuditModel.java
@@ -16,6 +16,7 @@
*/
package org.alfresco.repo.audit;
+import org.alfresco.repo.audit.model.TrueFalseUnset;
import org.aopalliance.intercept.MethodInvocation;
public interface MethodAuditModel
@@ -54,4 +55,11 @@ public interface MethodAuditModel
* @return
*/
public RecordOptions getAuditRecordOptions(MethodInvocation mi);
+
+ /**
+ * Should internal service class be logged.
+ *
+ * @return
+ */
+ public TrueFalseUnset getAuditInternalServiceMethods(MethodInvocation mi);
}
diff --git a/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml b/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml
index 9e40c7a787..acc837c69a 100644
--- a/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml
+++ b/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml
@@ -67,7 +67,7 @@
-
+
@@ -135,24 +135,34 @@
select
- audit_store
+ audit_store_byid
+ from
+ org.alfresco.repo.audit.hibernate.AuditSourceImpl as audit_store_byid
+ where
+ audit_store_byid =
+ (select max(audit_store.id)
from
org.alfresco.repo.audit.hibernate.AuditSourceImpl as audit_store
where
audit_store.application = :application and
audit_store.service is null and
- audit_store.method is null
+ audit_store.method is null)
select
- audit_store
+ audit_store_byid
+ from
+ org.alfresco.repo.audit.hibernate.AuditSourceImpl as audit_store_byid
+ where
+ audit_store_byid =
+ (select max(audit_store.id)
from
org.alfresco.repo.audit.hibernate.AuditSourceImpl as audit_store
where
audit_store.application = :application and
audit_store.service = :service and
- audit_store.method = :method
+ audit_store.method = :method)
diff --git a/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java b/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java
index c99fd0bb7c..d747a482d3 100644
--- a/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java
+++ b/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java
@@ -136,6 +136,49 @@ public abstract class AbstractAuditEntry
{
return recordOptions;
}
+
+
+ protected TrueFalseUnset getEffectiveAuditInternal()
+ {
+ TrueFalseUnset auditInternal;
+ if (checkEnabled() == TrueFalseUnset.TRUE)
+ {
+ auditInternal = getAuditInternalOrParentAuditInternal();
+ }
+ else
+ {
+ auditInternal = TrueFalseUnset.FALSE;
+ }
+ if(s_logger.isDebugEnabled())
+ {
+ s_logger.debug("... Effective audit internal is = "+auditInternal);
+ }
+ return auditInternal;
+ }
+
+ private TrueFalseUnset getAuditInternalOrParentAuditInternal()
+ {
+ TrueFalseUnset auditInternal = getAuditInternal();
+ if(s_logger.isDebugEnabled())
+ {
+ s_logger.debug("... ... audit internal is = "+auditInternal);
+ }
+ if (auditInternal == TrueFalseUnset.UNSET)
+ {
+ if (getParent() == null)
+ {
+ return TrueFalseUnset.UNSET;
+ }
+ else
+ {
+ return getParent().getAuditInternalOrParentAuditInternal();
+ }
+ }
+ else
+ {
+ return auditInternal;
+ }
+ }
protected AuditMode getEffectiveAuditMode()
{
diff --git a/source/java/org/alfresco/repo/audit/model/AuditEntry.java b/source/java/org/alfresco/repo/audit/model/AuditEntry.java
index 68678d200c..613da6578d 100644
--- a/source/java/org/alfresco/repo/audit/model/AuditEntry.java
+++ b/source/java/org/alfresco/repo/audit/model/AuditEntry.java
@@ -217,4 +217,23 @@ public class AuditEntry extends AbstractAuditEntry implements InitializingBean,
throw new UnsupportedOperationException();
}
+ public TrueFalseUnset getAuditInternalServiceMethods( MethodInvocation mi)
+ {
+ String serviceName = getPublicServiceIdentifier().getPublicServiceName(mi);
+ ServiceAuditEntry service = services.get(serviceName);
+ if(service != null)
+ {
+ return service.getAuditInternalServiceMethods( mi);
+ }
+ else
+ {
+ if(s_logger.isDebugEnabled())
+ {
+ s_logger.debug("No specific audit entry for service "+serviceName);
+ }
+ return getEffectiveAuditInternal();
+
+ }
+ }
+
}
diff --git a/source/java/org/alfresco/repo/audit/model/MethodAuditEntry.java b/source/java/org/alfresco/repo/audit/model/MethodAuditEntry.java
index a59d6b7a72..c38d36e5db 100644
--- a/source/java/org/alfresco/repo/audit/model/MethodAuditEntry.java
+++ b/source/java/org/alfresco/repo/audit/model/MethodAuditEntry.java
@@ -56,4 +56,13 @@ public class MethodAuditEntry extends AbstractNamedAuditEntry implements MethodA
throw new UnsupportedOperationException();
}
+ public TrueFalseUnset getAuditInternalServiceMethods(MethodInvocation mi)
+ {
+ if(s_logger.isDebugEnabled())
+ {
+ s_logger.debug("Evaluating if method is internally audited ..."+((ServiceAuditEntry)getParent()).getName()+"."+getName());
+ }
+ return getEffectiveAuditInternal();
+ }
+
}
diff --git a/source/java/org/alfresco/repo/audit/model/ServiceAuditEntry.java b/source/java/org/alfresco/repo/audit/model/ServiceAuditEntry.java
index 764f004044..e4458bb5ff 100644
--- a/source/java/org/alfresco/repo/audit/model/ServiceAuditEntry.java
+++ b/source/java/org/alfresco/repo/audit/model/ServiceAuditEntry.java
@@ -97,4 +97,22 @@ public class ServiceAuditEntry extends AbstractNamedAuditEntry implements Method
throw new UnsupportedOperationException();
}
+ public TrueFalseUnset getAuditInternalServiceMethods(MethodInvocation mi)
+ {
+ String methodName = mi.getMethod().getName();
+ MethodAuditEntry method = methods.get(methodName);
+ if (method != null)
+ {
+ return method.getAuditInternalServiceMethods(mi);
+ }
+ else
+ {
+ if(s_logger.isDebugEnabled())
+ {
+ s_logger.debug("Evaluating if service is internally audited (no specific setting) for "+getName()+"."+methodName);
+ }
+ return getEffectiveAuditInternal();
+ }
+ }
+
}
diff --git a/source/java/org/alfresco/repo/cache/InternalEhCacheManagerFactoryBean.java b/source/java/org/alfresco/repo/cache/InternalEhCacheManagerFactoryBean.java
index 3830803457..cf87c94d1f 100644
--- a/source/java/org/alfresco/repo/cache/InternalEhCacheManagerFactoryBean.java
+++ b/source/java/org/alfresco/repo/cache/InternalEhCacheManagerFactoryBean.java
@@ -44,7 +44,7 @@ import org.springframework.util.ResourceUtils;
* For Alfresco purposes, there are two files that are looked for:
*
*
classpath:alfresco/extension/ehcache-custom.xml, which will take precedence
- *
classpath:alfresco/ehcache.xml, which is the default shipped with Alfresco
+ *
classpath:alfresco/ehcache-default.xml, which is the default shipped with Alfresco
*
*
* The EHCache static singleton instance is used but ensuring that all access to the
diff --git a/source/java/org/alfresco/repo/content/AbstractContentStore.java b/source/java/org/alfresco/repo/content/AbstractContentStore.java
index 76ff24e12b..db7336a57c 100644
--- a/source/java/org/alfresco/repo/content/AbstractContentStore.java
+++ b/source/java/org/alfresco/repo/content/AbstractContentStore.java
@@ -109,7 +109,7 @@ public abstract class AbstractContentStore implements ContentStore
// extract the relative part of the URL
String path = contentUrl.substring(index);
// more extensive checks can be added in, but it seems overkill
- if (path.length() < 10)
+ if (path.length() < 8)
{
throw new AlfrescoRuntimeException(
"The content URL is invalid: \n" +
diff --git a/source/java/org/alfresco/repo/content/MimetypeMap.java b/source/java/org/alfresco/repo/content/MimetypeMap.java
index 272c1cb89d..473dea5253 100644
--- a/source/java/org/alfresco/repo/content/MimetypeMap.java
+++ b/source/java/org/alfresco/repo/content/MimetypeMap.java
@@ -56,6 +56,7 @@ public class MimetypeMap implements MimetypeService
public static final String MIMETYPE_IMAGE_GIF = "image/gif";
public static final String MIMETYPE_IMAGE_JPEG = "image/jpeg";
public static final String MIMETYPE_IMAGE_RGB = "image/x-rgb";
+ public static final String MIMETYPE_IMAGE_SVG = "image/svg";
public static final String MIMETYPE_JAVASCRIPT = "application/x-javascript";
public static final String MIMETYPE_ZIP = "application/zip";
// Open Document
diff --git a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java
index adfedf0767..de57d173c7 100644
--- a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java
+++ b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java
@@ -16,6 +16,7 @@
*/
package org.alfresco.repo.content.cleanup;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
@@ -27,10 +28,12 @@ import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.transaction.TransactionService;
+import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -116,26 +119,10 @@ public class ContentStoreCleaner
*/
private void checkProperties()
{
- if (dictionaryService == null)
- {
- throw new AlfrescoRuntimeException("Property 'dictionaryService' not set");
- }
- if (nodeDaoService == null)
- {
- throw new AlfrescoRuntimeException("Property 'nodeDaoService' not set");
- }
- if (transactionService == null)
- {
- throw new AlfrescoRuntimeException("Property 'transactionService' not set");
- }
- if (stores == null || stores.size() == 0)
- {
- throw new AlfrescoRuntimeException("Property 'stores' not set");
- }
- if (listeners == null)
- {
- throw new AlfrescoRuntimeException("Property 'listeners' not set");
- }
+ PropertyCheck.mandatory(this, "dictionaryService", dictionaryService);
+ PropertyCheck.mandatory(this, "nodeDaoService", nodeDaoService);
+ PropertyCheck.mandatory(this, "transactionService", transactionService);
+ PropertyCheck.mandatory(this, "listeners", listeners);
// check the protect days
if (protectDays < 0)
@@ -152,26 +139,27 @@ public class ContentStoreCleaner
private Set getValidUrls()
{
+ final DataTypeDefinition contentDataType = dictionaryService.getDataType(DataTypeDefinition.CONTENT);
// wrap to make the request in a transaction
- TransactionWork> getUrlsWork = new TransactionWork>()
+ TransactionWork> getUrlsWork = new TransactionWork>()
{
- public List doWork() throws Exception
+ public List doWork() throws Exception
{
- return nodeDaoService.getContentDataStrings();
+ return nodeDaoService.getPropertyValuesByActualType(contentDataType);
};
};
// execute in READ-ONLY txn
- List contentDataStrings = TransactionUtil.executeInUserTransaction(
+ List values = TransactionUtil.executeInUserTransaction(
transactionService,
getUrlsWork,
true);
// get all valid URLs
- Set validUrls = new HashSet(contentDataStrings.size());
+ Set validUrls = new HashSet(values.size());
// convert the strings to objects and extract the URL
- for (String contentDataString : contentDataStrings)
+ for (Serializable value : values)
{
- ContentData contentData = ContentData.createContentProperty(contentDataString);
+ ContentData contentData = (ContentData) value;
if (contentData.getContentUrl() != null)
{
// a URL was present
diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java
index 468ba3e5f0..42ba8f27d3 100644
--- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java
@@ -19,7 +19,10 @@ package org.alfresco.repo.content.transform;
import java.io.File;
import java.io.IOException;
import java.net.URL;
-import java.util.List;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TreeSet;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.filestore.FileContentReader;
@@ -120,45 +123,71 @@ public abstract class AbstractContentTransformerTest extends BaseSpringTest
* case where optimizations are being done around the selection of the most
* appropriate transformer, different transformers could be used during the iteration
* process.
+ *
+ * Results for the transformations are dumped to a temporary file named
+ * AbstractContentTransformerTest-results-1234.txt.
*/
public void testAllConversions() throws Exception
{
+ StringBuilder sb = new StringBuilder(2048);
+ sb.append("Mimetype Conversion Tests \n")
+ .append("========================= \n")
+ .append(" Date: ").append(new Date()).append("\n")
+ .append("\n");
+
// get all mimetypes
- List mimetypes = mimetypeMap.getMimetypes();
+ Set mimetypes = new TreeSet(mimetypeMap.getMimetypes());
for (String sourceMimetype : mimetypes)
{
// attempt to get a source file for each mimetype
String sourceExtension = mimetypeMap.getExtension(sourceMimetype);
- File sourceFile = AbstractContentTransformerTest.loadQuickTestFile(sourceExtension);
- if (sourceFile == null)
- {
- continue; // no test file available for that extension
- }
+
+ sb.append(" Source Extension: ").append(sourceExtension).append("\n");
// attempt to convert to every other mimetype
for (String targetMimetype : mimetypes)
{
ContentWriter targetWriter = null;
// construct a reader onto the source file
+ String targetExtension = mimetypeMap.getExtension(targetMimetype);
+
+ // must we test the transformation?
+ ContentTransformer transformer = getTransformer(sourceMimetype, targetMimetype);
+ if (transformer == null || transformer.getReliability(sourceMimetype, targetMimetype) <= 0.0)
+ {
+ // no transformer
+ continue;
+ }
+
+ // dump
+ sb.append(" Target Extension: ").append(targetExtension);
+ sb.append(" <").append(transformer.getClass().getSimpleName()).append(">");
+
+ // is there a test file for this conversion?
+ File sourceFile = AbstractContentTransformerTest.loadQuickTestFile(sourceExtension);
+ if (sourceFile == null)
+ {
+ sb.append(" \n");
+ continue; // no test file available for that extension
+ }
ContentReader sourceReader = new FileContentReader(sourceFile);
// perform the transformation several times so that we get a good idea of performance
int count = 0;
+ long before = System.currentTimeMillis();
+ Set transformerClasses = new HashSet(2);
for (int i = 0; i < 5; i++)
{
- // must we test the transformation?
- ContentTransformer transformer = getTransformer(sourceMimetype, targetMimetype);
- if (transformer == null)
+ // get the transformer repeatedly as it might be different each time around
+ transformer = getTransformer(sourceMimetype, targetMimetype);
+ // must we report on this class?
+ if (!transformerClasses.contains(transformer.getClass().getName()))
{
- break; // test is not required
+ transformerClasses.add(transformer.getClass().getName());
+ sb.append(" <").append(transformer.getClass().getSimpleName()).append(">");
}
- else if (transformer.getReliability(sourceMimetype, targetMimetype) <= 0.0)
- {
- break; // not reliable for this transformation
- }
-
+
// make a writer for the target file
- String targetExtension = mimetypeMap.getExtension(targetMimetype);
File targetFile = TempFileProvider.createTempFile(
getClass().getSimpleName() + "_" + getName() + "_" + sourceExtension + "_",
"." + targetExtension);
@@ -198,6 +227,11 @@ public abstract class AbstractContentTransformerTest extends BaseSpringTest
// increment count
count++;
}
+ long after = System.currentTimeMillis();
+ double average = (double) (after - before) / (double) count;
+
+ // dump
+ sb.append(String.format(" average %10.0f ms", average)).append("\n");
if (logger.isDebugEnabled())
{
@@ -209,5 +243,11 @@ public abstract class AbstractContentTransformerTest extends BaseSpringTest
}
}
}
+
+ // dump to file
+ File outputFile = TempFileProvider.createTempFile("AbstractContentTransformerTest-results-", ".txt");
+ ContentWriter outputWriter = new FileContentWriter(outputFile);
+ outputWriter.setEncoding("UTF8");
+ outputWriter.putContent(sb.toString());
}
}
diff --git a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java
index 12d016db23..a70d31d106 100644
--- a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java
@@ -16,9 +16,16 @@
*/
package org.alfresco.repo.content.transform;
+import java.io.File;
+
import net.sf.jooreports.openoffice.connection.OpenOfficeConnection;
import org.alfresco.repo.content.MimetypeMap;
+import org.alfresco.repo.content.filestore.FileContentReader;
+import org.alfresco.repo.content.filestore.FileContentWriter;
+import org.alfresco.service.cmr.repository.ContentReader;
+import org.alfresco.service.cmr.repository.ContentWriter;
+import org.alfresco.util.TempFileProvider;
/**
* @see org.alfresco.repo.content.transform.OpenOfficeContentTransformer
@@ -75,4 +82,24 @@ public class OpenOfficeContentTransformerTest extends AbstractContentTransformer
reliability = transformer.getReliability(MimetypeMap.MIMETYPE_WORD, MimetypeMap.MIMETYPE_TEXT_PLAIN);
assertEquals("Mimetype should be supported", 1.0, reliability);
}
+
+ /**
+ * Test what is up with HTML to PDF
+ */
+ public void testHtmlToPdf() throws Exception
+ {
+ if (!transformer.isConnected())
+ {
+ // no connection
+ return;
+ }
+ File htmlSourceFile = loadQuickTestFile("html");
+ File pdfTargetFile = TempFileProvider.createTempFile(getName() + "-target-", ".pdf");
+ ContentReader reader = new FileContentReader(htmlSourceFile);
+ reader.setMimetype(MimetypeMap.MIMETYPE_HTML);
+ ContentWriter writer = new FileContentWriter(pdfTargetFile);
+ writer.setMimetype(MimetypeMap.MIMETYPE_PDF);
+
+ transformer.transform(reader, writer);
+ }
}
diff --git a/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformer.java b/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformer.java
index 852f9194b0..bb11c7d662 100644
--- a/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformer.java
+++ b/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformer.java
@@ -145,6 +145,10 @@ public abstract class AbstractImageMagickContentTransformer extends AbstractCont
{
return false; // rgb extension doesn't work
}
+ else if (mimetype.equals(MimetypeMap.MIMETYPE_IMAGE_SVG))
+ {
+ return false; // svg extension doesn't work
+ }
else
{
return true;
diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java b/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java
index 2b9722b49e..f9cd844d6c 100644
--- a/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java
+++ b/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java
@@ -81,7 +81,7 @@ public class DictionaryComponent implements DictionaryService
Collection propertyTypes = new ArrayList();
for (QName model : getAllModels())
{
- propertyTypes.addAll(getAspects(model));
+ propertyTypes.addAll(getDataTypes(model));
}
return propertyTypes;
}
diff --git a/source/java/org/alfresco/repo/dictionary/M2Model.java b/source/java/org/alfresco/repo/dictionary/M2Model.java
index 4dad74222a..c4c8752aa4 100644
--- a/source/java/org/alfresco/repo/dictionary/M2Model.java
+++ b/source/java/org/alfresco/repo/dictionary/M2Model.java
@@ -202,7 +202,7 @@ public class M2Model
M2Type type = getType(name);
if (type != null)
{
- types.remove(types);
+ types.remove(type);
}
}
diff --git a/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml b/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml
index fc8748f662..ba51937ef7 100644
--- a/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml
+++ b/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml
@@ -16,7 +16,7 @@
- org.apache.lucene.analysis.standard.StandardAnalyzer
+ org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyserjava.lang.Object
diff --git a/source/java/org/alfresco/repo/domain/PropertyValue.java b/source/java/org/alfresco/repo/domain/PropertyValue.java
index f4fad1fa2a..bd1803d20f 100644
--- a/source/java/org/alfresco/repo/domain/PropertyValue.java
+++ b/source/java/org/alfresco/repo/domain/PropertyValue.java
@@ -19,6 +19,7 @@ package org.alfresco.repo.domain;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@@ -438,19 +439,32 @@ public class PropertyValue implements Cloneable, Serializable
*
* @return Returns the ValueType - never null
*/
- private ValueType makeValueType(QName typeQName)
+ private static ValueType makeValueType(QName typeQName)
{
ValueType valueType = valueTypesByPropertyType.get(typeQName);
if (valueType == null)
{
throw new AlfrescoRuntimeException(
"Property type not recognised: \n" +
- " type: " + typeQName + "\n" +
- " property: " + this);
+ " type: " + typeQName);
}
return valueType;
}
+ /**
+ * Given an actual type qualified name, returns the String that represents it in
+ * the database.
+ *
+ * @param typeQName the type qualified name
+ * @return Returns the String representation of the type,
+ * e.g. CONTENT for type d:content.
+ */
+ public static String getActualTypeString(QName typeQName)
+ {
+ ValueType valueType = makeValueType(typeQName);
+ return valueType.toString();
+ }
+
@Override
public boolean equals(Object obj)
{
@@ -632,15 +646,16 @@ public class PropertyValue implements Cloneable, Serializable
* @return Returns the value of this property as the desired type, or a Collection
* of values of the required type
*
- * @throws java.lang.UnsupportedOperationException if the value cannot be converted to the
- * type given
+ * @throws AlfrescoRuntimeException
+ * if the type given is not recognized
+ * @throws org.alfresco.service.cmr.repository.datatype.TypeConversionException
+ * if the conversion to the required type fails
*
* @see DataTypeDefinition#ANY The static qualified names for the types
*/
public Serializable getValue(QName typeQName)
{
// first check for null
-
ValueType requiredType = makeValueType(typeQName);
if (requiredType == ValueType.SERIALIZABLE)
{
@@ -680,6 +695,24 @@ public class PropertyValue implements Cloneable, Serializable
return ret;
}
+ /**
+ * Gets the value or values as a guaranteed collection.
+ *
+ * @see #getValue(QName)
+ */
+ public Collection getCollection(QName typeQName)
+ {
+ Serializable value = getValue(typeQName);
+ if (value instanceof Collection)
+ {
+ return (Collection) value;
+ }
+ else
+ {
+ return Collections.singletonList(value);
+ }
+ }
+
public boolean getBooleanValue()
{
if (booleanValue == null)
diff --git a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml
index 15fe0ed614..96fd1aee85 100644
--- a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml
+++ b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml
@@ -364,15 +364,19 @@
transaction.changeTxnId = :changeTxnId
-
- select distinct
- props.stringValue
+
+ select
+ node
from
org.alfresco.repo.domain.hibernate.NodeImpl as node
join
- node.properties props
+ node.properties prop
where
- props.stringValue like 'contentUrl%'
+ (
+ prop.actualType = :actualTypeString or
+ prop.actualType = 'SERIALIZABLE'
+ ) and
+ prop.persistedType != 'NULL'
diff --git a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java
index c3822a51bc..64d718da6f 100644
--- a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java
+++ b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java
@@ -314,9 +314,13 @@ public class SchemaBootstrap implements ApplicationListener
}
if (create)
{
+ // Get the dialect
+ final Dialect dialect = Dialect.getDialect(cfg.getProperties());
+ String dialectStr = dialect.getClass().getName();
+
// the applied patch table is missing - we assume that all other tables are missing
// perform a full update using Hibernate-generated statements
- File tempFile = TempFileProvider.createTempFile("AlfrescoSchemaCreate", ".sql");
+ File tempFile = TempFileProvider.createTempFile("AlfrescoSchemaCreate-" + dialectStr + "-", ".sql");
dumpSchemaCreate(cfg, tempFile);
FileInputStream tempInputStream = new FileInputStream(tempFile);
executeScriptFile(cfg, connection, tempInputStream, tempFile.getPath());
diff --git a/source/java/org/alfresco/repo/jscript/Node.java b/source/java/org/alfresco/repo/jscript/Node.java
index 25226c1629..daeb82ed3f 100644
--- a/source/java/org/alfresco/repo/jscript/Node.java
+++ b/source/java/org/alfresco/repo/jscript/Node.java
@@ -79,6 +79,11 @@ import org.springframework.util.StringUtils;
*/
public class Node implements Serializable, Scopeable
{
+ /**
+ * Comment for serialVersionUID
+ */
+ private static final long serialVersionUID = -3378946227712939600L;
+
private static Log logger = LogFactory.getLog(Node.class);
private final static String NAMESPACE_BEGIN = "" + QName.NAMESPACE_BEGIN;
@@ -885,6 +890,43 @@ public class Node implements Serializable, Scopeable
this.services.getPermissionService().deletePermission(this.nodeRef, authority, permission);
}
+ // -------------
+ // Ownership API
+
+ /**
+ * Set the owner of the node
+ */
+ public void setOwner(String userId)
+ {
+ this.services.getOwnableService().setOwner(this.nodeRef, userId);
+ }
+
+ /**
+ * Take ownership of the node.
+ */
+ public void takeOwnership()
+ {
+ this.services.getOwnableService().takeOwnership(this.nodeRef);
+ }
+
+ /**
+ * Get the owner of the node.
+ * @return
+ */
+ public String getOwner()
+ {
+ return this.services.getOwnableService().getOwner(this.nodeRef);
+ }
+
+ /**
+ * Make owner available as a property.
+ *
+ * @return
+ */
+ public String jsGet_owner()
+ {
+ return getOwner();
+ }
// ------------------------------------------------------------------------------
// Create and Modify API
@@ -1645,8 +1687,11 @@ public class Node implements Serializable, Scopeable
{
if (this.nodeService.exists(nodeRef))
{
+ // TODO: DC: Allow debug output of property values - for now it's disabled as this could potentially
+ // follow a large network of nodes. Unfortunately, JBPM issues unprotected debug statements
+ // where node.toString is used - will request this is fixed in next release of JBPM.
return "Node Type: " + getType() +
- "\nNode Properties: " + this.getProperties().toString() +
+ "\nNode Properties: " + this.getProperties().size() +
"\nNode Aspects: " + this.getAspects().toString();
}
else
diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java
index 4fe89d582b..6d5eff338d 100644
--- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java
+++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java
@@ -73,7 +73,11 @@ public class FileFolderServiceImpl implements FileFolderService
/** Shallow search for all files and folders */
private static final String LUCENE_QUERY_SHALLOW_ALL =
"+PARENT:\"${cm:parent}\"" +
- "-TYPE:\"" + ContentModel.TYPE_SYSTEM_FOLDER + "\" ";
+ "-TYPE:\"" + ContentModel.TYPE_SYSTEM_FOLDER + "\" " +
+ "+(" +
+ "TYPE:\"" + ContentModel.TYPE_CONTENT + "\" " +
+ "TYPE:\"" + ContentModel.TYPE_FOLDER + "\" " +
+ ")";
/** Shallow search for all files and folders */
private static final String LUCENE_QUERY_SHALLOW_FOLDERS =
diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java
index 279cdb5922..c06659c665 100644
--- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java
+++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java
@@ -28,6 +28,7 @@ import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.node.integrity.IntegrityChecker;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileExistsException;
@@ -91,6 +92,9 @@ public class FileFolderServiceImplTest extends TestCase
txn = transactionService.getUserTransaction();
txn.begin();
+ // downgrade integrity
+ IntegrityChecker.setWarnInTransaction();
+
// authenticate
authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
diff --git a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java
index f6de57d293..6dd08e7ca8 100644
--- a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java
+++ b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java
@@ -35,6 +35,7 @@ import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.domain.hibernate.ChildAssocImpl;
import org.alfresco.repo.domain.hibernate.NodeImpl;
import org.alfresco.repo.node.db.NodeDaoService;
+import org.alfresco.repo.node.integrity.IntegrityChecker;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
@@ -161,6 +162,9 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
StoreRef.PROTOCOL_WORKSPACE,
"Test_" + System.currentTimeMillis());
rootNodeRef = nodeService.getRootNode(storeRef);
+
+ // downgrade integrity checks
+ IntegrityChecker.setWarnInTransaction();
}
@Override
diff --git a/source/java/org/alfresco/repo/node/PerformanceNodeServiceTest.java b/source/java/org/alfresco/repo/node/PerformanceNodeServiceTest.java
index 8935297d7c..51810f9c1f 100644
--- a/source/java/org/alfresco/repo/node/PerformanceNodeServiceTest.java
+++ b/source/java/org/alfresco/repo/node/PerformanceNodeServiceTest.java
@@ -27,6 +27,7 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.dictionary.DictionaryComponent;
import org.alfresco.repo.dictionary.DictionaryDAO;
import org.alfresco.repo.dictionary.M2Model;
+import org.alfresco.repo.node.integrity.IntegrityChecker;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
@@ -160,6 +161,7 @@ public class PerformanceNodeServiceTest extends TestCase
{
public Object doWork()
{
+ IntegrityChecker.setWarnInTransaction();
buildNodeChildren(rootNodeRef, 1, testDepth, testChildCount);
return null;
}
diff --git a/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java b/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java
index 489b65a72f..b20eedd85e 100644
--- a/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java
+++ b/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java
@@ -29,6 +29,7 @@ import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.StoreArchiveMap;
import org.alfresco.repo.node.archive.RestoreNodeReport.RestoreStatus;
+import org.alfresco.repo.node.integrity.IntegrityChecker;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.ServiceRegistry;
@@ -37,7 +38,6 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
-import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
@@ -114,6 +114,9 @@ public class ArchiveAndRestoreTest extends TestCase
txn = transactionService.getUserTransaction();
txn.begin();
+ // downgrade integrity checks
+ IntegrityChecker.setWarnInTransaction();
+
try
{
authenticationComponent.setSystemUserAsCurrentUser();
diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
index 907d1e65b5..d4efe11708 100644
--- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
+++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
@@ -40,7 +40,6 @@ import org.alfresco.repo.domain.Store;
import org.alfresco.repo.node.AbstractNodeServiceImpl;
import org.alfresco.repo.node.StoreArchiveMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
-import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
@@ -1461,15 +1460,12 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
nodeToMove.setStore(store);
NodeRef newNodeRef = nodeToMove.getNodeRef();
- String txnId = AlfrescoTransactionSupport.getTransactionId();
// update old status
NodeStatus oldNodeStatus = nodeDaoService.getNodeStatus(oldNodeRef, true);
oldNodeStatus.setNode(null);
- oldNodeStatus.getTransaction().setChangeTxnId(txnId);
// create the new status
NodeStatus newNodeStatus = nodeDaoService.getNodeStatus(newNodeRef, true);
newNodeStatus.setNode(nodeToMove);
- newNodeStatus.getTransaction().setChangeTxnId(txnId);
}
}
diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java
index 43341b58c3..d99ddb00fe 100644
--- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java
+++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java
@@ -17,6 +17,7 @@
package org.alfresco.repo.node.db;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -30,6 +31,8 @@ import org.alfresco.repo.node.BaseNodeServiceTest;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -47,6 +50,7 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
{
private TransactionService txnService;
private NodeDaoService nodeDaoService;
+ private DictionaryService dictionaryService;
protected NodeService getNodeService()
{
@@ -59,6 +63,7 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
super.onSetUpInTransaction();
txnService = (TransactionService) applicationContext.getBean("transactionComponent");
nodeDaoService = (NodeDaoService) applicationContext.getBean("nodeDaoService");
+ dictionaryService = (DictionaryService) applicationContext.getBean("dictionaryService");
}
/**
@@ -258,18 +263,34 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
/**
* Checks that the string_value retrieval against a property type is working
*/
- public void testGetContentDataStringValues() throws Exception
+ public void testGetContentDataValues() throws Exception
{
- ContentData contentData = new ContentData("abc", MimetypeMap.MIMETYPE_TEXT_PLAIN, 0L, null);
- // put this in as a random property
+ final DataTypeDefinition contentDataType = dictionaryService.getDataType(DataTypeDefinition.CONTENT);
+
+ ContentData contentDataSingle = new ContentData("url-single", MimetypeMap.MIMETYPE_TEXT_PLAIN, 0L, null);
+ ContentData contentDataMultiple = new ContentData("url-multiple", MimetypeMap.MIMETYPE_TEXT_PLAIN, 0L, null);
+ // put this in as a random single property
nodeService.setProperty(
rootNodeRef,
- QName.createQName(NAMESPACE, "random"),
- contentData);
+ QName.createQName(NAMESPACE, "random-single"),
+ contentDataSingle);
+
+ // create a collection of mixed types
+ ArrayList collection = new ArrayList(3);
+ collection.add("abc");
+ collection.add(new Integer(123));
+ collection.add(contentDataMultiple);
+ nodeService.setProperty(
+ rootNodeRef,
+ QName.createQName(NAMESPACE, "random-multiple"),
+ collection);
+
// get a list of all content values
- List contentDataStrings = nodeDaoService.getContentDataStrings();
- assertNotNull(contentDataStrings);
- assertTrue("ContentData not represented as a String in results",
- contentDataStrings.contains(contentData.toString()));
+ List allContentDatas = nodeDaoService.getPropertyValuesByActualType(contentDataType);
+ assertTrue("At least two instances expected", allContentDatas.size() >= 2);
+ assertTrue("Single content data not present in results",
+ allContentDatas.contains(contentDataSingle));
+ assertTrue("Multi-valued buried content data not present in results",
+ allContentDatas.contains(contentDataMultiple));
}
}
diff --git a/source/java/org/alfresco/repo/node/db/NodeDaoService.java b/source/java/org/alfresco/repo/node/db/NodeDaoService.java
index 3fba9af4f9..25e90f432a 100644
--- a/source/java/org/alfresco/repo/node/db/NodeDaoService.java
+++ b/source/java/org/alfresco/repo/node/db/NodeDaoService.java
@@ -16,6 +16,7 @@
*/
package org.alfresco.repo.node.db;
+import java.io.Serializable;
import java.util.Collection;
import java.util.List;
@@ -24,6 +25,7 @@ import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.NodeAssoc;
import org.alfresco.repo.domain.NodeStatus;
import org.alfresco.repo.domain.Store;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -76,11 +78,12 @@ public interface NodeDaoService
* null is returned.
*
* @param nodeRef the node reference
- * @param create true to create the entity if it doesn't exist
+ * @param create true if the node status is to be updated in the transaction, i.e.
+ * the current transaction must be assigned to the status
* @return Returns the node status if the node exists or once existed, otherwise
* returns null if create == false
*/
- public NodeStatus getNodeStatus(NodeRef nodeRef, boolean create);
+ public NodeStatus getNodeStatus(NodeRef nodeRef, boolean update);
/**
* Sets the current transaction ID on the node status. Note that the node
@@ -224,10 +227,10 @@ public interface NodeDaoService
public void deleteNodeAssoc(NodeAssoc assoc);
/**
- * Fetch all content data strings. These are all string values that begin
- * with contentUrl=.
+ * Fetch all property values for the given type definition. This will also dig out values that
+ * were persisted as type d:any.
*
- * @return Returns the string values for content data
+ * @return Returns the values for the given type definition
*/
- public List getContentDataStrings();
+ public List getPropertyValuesByActualType(DataTypeDefinition actualDataTypeDefinition);
}
diff --git a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java
index c46fecd530..3c9f349502 100644
--- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java
+++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java
@@ -22,10 +22,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import java.util.zip.CRC32;
import org.alfresco.error.AlfrescoRuntimeException;
@@ -35,6 +33,7 @@ import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.NodeAssoc;
import org.alfresco.repo.domain.NodeKey;
import org.alfresco.repo.domain.NodeStatus;
+import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.domain.Server;
import org.alfresco.repo.domain.Store;
import org.alfresco.repo.domain.StoreKey;
@@ -48,19 +47,25 @@ import org.alfresco.repo.domain.hibernate.StoreImpl;
import org.alfresco.repo.domain.hibernate.TransactionImpl;
import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
+import org.alfresco.repo.transaction.TransactionAwareSingleton;
import org.alfresco.repo.transaction.TransactionalDao;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
import org.alfresco.service.cmr.repository.AssociationExistsException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
+import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
+import org.alfresco.service.cmr.repository.datatype.TypeConverter;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.ObjectDeletedException;
import org.hibernate.Query;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
@@ -83,7 +88,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
private static final String QUERY_GET_NODE_ASSOCS_TO_AND_FROM = "node.GetNodeAssocsToAndFrom";
private static final String QUERY_GET_TARGET_ASSOCS = "node.GetTargetAssocs";
private static final String QUERY_GET_SOURCE_ASSOCS = "node.GetSourceAssocs";
- private static final String QUERY_GET_CONTENT_DATA_STRINGS = "node.GetContentDataStrings";
+ private static final String QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_ACTUAL_TYPE = "node.GetNodesWithPropertyValuesByActualType";
private static final String QUERY_GET_SERVER_BY_IPADDRESS = "server.getServerByIpAddress";
private static Log logger = LogFactory.getLog(HibernateNodeDaoServiceImpl.class);
@@ -91,9 +96,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
/** a uuid identifying this unique instance */
private final String uuid;
- private final ReadLock serverReadLock;
- private final WriteLock serverWriteLock;
- private Server server;
+ private static TransactionAwareSingleton serverIdSingleton = new TransactionAwareSingleton();
/**
*
@@ -101,10 +104,6 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
public HibernateNodeDaoServiceImpl()
{
this.uuid = GUID.generate();
-
- ReentrantReadWriteLock serverReadWriteLock = new ReentrantReadWriteLock();
- serverReadLock = serverReadWriteLock.readLock();
- serverWriteLock = serverReadWriteLock.writeLock();
}
/**
@@ -137,21 +136,16 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
*/
private Server getServer()
{
- // get readlock
- serverReadLock.lock();
- try
+ Long serverId = serverIdSingleton.get();
+ Server server = null;
+ if (serverId != null)
{
+ server = (Server) getSession().get(ServerImpl.class, serverId);
if (server != null)
{
return server;
}
}
- finally
- {
- serverReadLock.unlock();
- }
- // get the write lock
- serverWriteLock.lock();
try
{
final String ipAddress = InetAddress.getLocalHost().getHostAddress();
@@ -185,16 +179,15 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
}
}
}
+ // push the value into the singleton
+ serverIdSingleton.put(server.getId());
+
return server;
}
catch (Exception e)
{
throw new AlfrescoRuntimeException("Failed to create server instance", e);
}
- finally
- {
- serverWriteLock.unlock();
- }
}
private static final String RESOURCE_KEY_TRANSACTION_ID = "hibernate.transaction.id";
@@ -307,7 +300,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
/**
* Fetch the node status, if it exists
*/
- public NodeStatus getNodeStatus(NodeRef nodeRef, boolean create)
+ public NodeStatus getNodeStatus(NodeRef nodeRef, boolean update)
{
NodeKey nodeKey = new NodeKey(nodeRef);
NodeStatus status = null;
@@ -325,13 +318,18 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
throw e;
}
// create if necessary
- if (status == null && create)
+ if (status == null && update)
{
status = new NodeStatusImpl();
status.setKey(nodeKey);
status.setTransaction(getCurrentTransaction());
getHibernateTemplate().save(status);
}
+ else if (status != null && update)
+ {
+ // update the transaction
+ status.setTransaction(getCurrentTransaction());
+ }
// done
return status;
}
@@ -934,18 +932,62 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
getSession().flush();
}
- @SuppressWarnings("unchecked")
- public List getContentDataStrings()
+ public List getPropertyValuesByActualType(DataTypeDefinition actualDataTypeDefinition)
{
+ // get the in-database string representation of the actual type
+ QName typeQName = actualDataTypeDefinition.getName();
+ final String actualTypeString = PropertyValue.getActualTypeString(typeQName);
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
- Query query = session.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CONTENT_DATA_STRINGS);
- return query.list();
+ Query query = session
+ .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_ACTUAL_TYPE)
+ .setString("actualTypeString", actualTypeString);
+ return query.scroll(ScrollMode.FORWARD_ONLY);
}
};
- List queryResults = (List) getHibernateTemplate().execute(callback);
- return queryResults;
+ ScrollableResults results = (ScrollableResults) getHibernateTemplate().execute(callback);
+ // Loop through, extracting content URLs
+ List convertedValues = new ArrayList(1000);
+ TypeConverter converter = DefaultTypeConverter.INSTANCE;
+ while(results.next())
+ {
+ Node node = (Node) results.get()[0];
+ // loop through all the node properties
+ Map properties = node.getProperties();
+ for (PropertyValue propertyValue : properties.values())
+ {
+ // ignore nulls
+ if (propertyValue == null)
+ {
+ continue;
+ }
+ // Get the actual value(s) as a collection
+ Collection values = propertyValue.getCollection(DataTypeDefinition.ANY);
+ // attempt to convert instance in the collection
+ for (Serializable value : values)
+ {
+ // ignore nulls (null entries in collections)
+ if (value == null)
+ {
+ continue;
+ }
+ try
+ {
+ Serializable convertedValue = (Serializable) converter.convert(actualDataTypeDefinition, value);
+ // it converted, so add it
+ convertedValues.add(convertedValue);
+ }
+ catch (Throwable e)
+ {
+ // The value can't be converted - forget it
+ }
+ }
+ }
+ // evict all data from the session
+ getSession().clear();
+ }
+ return convertedValues;
}
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java b/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java
index e93ff18425..6f7be2bda8 100644
--- a/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java
+++ b/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java
@@ -88,6 +88,8 @@ public class IntegrityChecker
/** key against which the set of events is stored in the current transaction */
private static final String KEY_EVENT_SET = "IntegrityChecker.EventSet";
+ /** key to store the local flag to disable integrity errors, i.e. downgrade to warnings */
+ private static final String KEY_WARN_IN_TRANSACTION = "IntegrityChecker.WarnInTransaction";
private PolicyComponent policyComponent;
private DictionaryService dictionaryService;
@@ -97,6 +99,36 @@ public class IntegrityChecker
private int maxErrorsPerTransaction;
private boolean traceOn;
+ /**
+ * Downgrade violations to warnings within the current transaction. This is temporary and
+ * is dependent on there being a current transaction active against the
+ * current thread. When set, this will override the global
+ * {@link #setFailOnViolation(boolean) failure behaviour}.
+ */
+ public static void setWarnInTransaction()
+ {
+ AlfrescoTransactionSupport.bindResource(KEY_WARN_IN_TRANSACTION, Boolean.TRUE);
+ }
+
+ /**
+ * @return Returns true if the current transaction should only warn on violations.
+ * If false, the global setting will take effect.
+ *
+ * @see #setWarnInTransaction()
+ */
+ public static boolean isWarnInTransaction()
+ {
+ Boolean warnInTransaction = (Boolean) AlfrescoTransactionSupport.getResource(KEY_WARN_IN_TRANSACTION);
+ if (warnInTransaction == null || warnInTransaction == Boolean.FALSE)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
/**
*/
public IntegrityChecker()
@@ -572,7 +604,8 @@ public class IntegrityChecker
}
sb.append("\n").append(failure);
}
- if (failOnViolation)
+ boolean warnOnly = IntegrityChecker.isWarnInTransaction();
+ if (failOnViolation && !warnOnly)
{
logger.error(sb.toString());
throw new IntegrityException(failures);
diff --git a/source/java/org/alfresco/repo/node/integrity/IntegrityTest.java b/source/java/org/alfresco/repo/node/integrity/IntegrityTest.java
index 93c9ac253f..724393d11d 100644
--- a/source/java/org/alfresco/repo/node/integrity/IntegrityTest.java
+++ b/source/java/org/alfresco/repo/node/integrity/IntegrityTest.java
@@ -198,6 +198,18 @@ public class IntegrityTest extends TestCase
assertNotNull("Static IntegrityChecker not created", integrityChecker);
}
+ public void testTemporaryDowngrading() throws Exception
+ {
+ assertEquals("Per-transaction override not correct", false, IntegrityChecker.isWarnInTransaction());
+ // create bad node
+ NodeRef nodeRef = createNode("abc", TEST_TYPE_WITH_PROPERTIES, null);
+ // switch it off
+ IntegrityChecker.setWarnInTransaction();
+ assertEquals("Per-transaction override not correct", true, IntegrityChecker.isWarnInTransaction());
+ // now, only warnings should occur
+ checkIntegrityNoFailure();
+ }
+
public void testCreateWithoutProperties() throws Exception
{
NodeRef nodeRef = createNode("abc", TEST_TYPE_WITH_PROPERTIES, null);
diff --git a/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java b/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java
index 79b87c0336..088524f6fc 100644
--- a/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java
+++ b/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java
@@ -141,6 +141,14 @@ public class OwnableServiceTest extends TestCase
permissionService.setInheritParentPermissions(testNode, false);
+
+ assertEquals(AccessStatus.DENIED, permissionService.hasPermission(rootNodeRef, PermissionService.TAKE_OWNERSHIP));
+ assertEquals(AccessStatus.DENIED, permissionService.hasPermission(rootNodeRef, PermissionService.SET_OWNER));
+ assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode, PermissionService.TAKE_OWNERSHIP));
+ assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode, PermissionService.SET_OWNER));
+
+ permissionService.setPermission(rootNodeRef, "andy", PermissionService.WRITE_PROPERTIES, true);
+
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(rootNodeRef, PermissionService.TAKE_OWNERSHIP));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(rootNodeRef, PermissionService.SET_OWNER));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode, PermissionService.TAKE_OWNERSHIP));
diff --git a/source/java/org/alfresco/repo/policy/TransactionBehaviourQueue.java b/source/java/org/alfresco/repo/policy/TransactionBehaviourQueue.java
index bf46e807aa..f317dd14ef 100644
--- a/source/java/org/alfresco/repo/policy/TransactionBehaviourQueue.java
+++ b/source/java/org/alfresco/repo/policy/TransactionBehaviourQueue.java
@@ -25,7 +25,6 @@ import java.util.Queue;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.policy.Policy.Arg;
-import org.alfresco.repo.rule.RuleTransactionListener;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionListener;
import org.alfresco.util.GUID;
@@ -214,7 +213,7 @@ public class TransactionBehaviourQueue implements TransactionListener
{
return true;
}
- if (obj instanceof RuleTransactionListener)
+ if (obj instanceof TransactionBehaviourQueue)
{
TransactionBehaviourQueue that = (TransactionBehaviourQueue) obj;
return (this.id.equals(that.id));
diff --git a/source/java/org/alfresco/repo/search/IndexerSPI.java b/source/java/org/alfresco/repo/search/IndexerSPI.java
index 82a6e311ee..695c177901 100644
--- a/source/java/org/alfresco/repo/search/IndexerSPI.java
+++ b/source/java/org/alfresco/repo/search/IndexerSPI.java
@@ -22,6 +22,6 @@ public interface IndexerSPI extends Indexer
{
public void registerCallBack(FTSIndexerAware callBack);
- public void updateFullTextSearch(int i);
+ public int updateFullTextSearch(int i);
}
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java
index d810438117..593436647a 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java
@@ -29,13 +29,13 @@ import org.alfresco.service.namespace.QName;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.WhitespaceAnalyzer;
-import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser;
/**
* Analyse properties according to the property definition.
*
* The default is to use the standard tokeniser. The tokeniser should not have
- * been called when indexeing properties that require no tokenisation. (tokenise
+ * been called when indexing properties that require no tokenisation. (tokenise
* should be set to false when adding the field to the document)
*
* @author andyh
@@ -60,7 +60,7 @@ public class LuceneAnalyser extends Analyzer
*/
public LuceneAnalyser(DictionaryService dictionaryService)
{
- this(new StandardAnalyzer());
+ this(new AlfrescoStandardAnalyser());
this.dictionaryService = dictionaryService;
}
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl.java
index fc1c41ec58..91310ecfcd 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl.java
@@ -1696,13 +1696,13 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
return false;
}
- public void updateFullTextSearch(int size) throws LuceneIndexException
+ public int updateFullTextSearch(int size) throws LuceneIndexException
{
checkAbleToDoWork(true, false);
if (!mainIndexExists())
{
remainingCount = size;
- return;
+ return 0;
}
try
{
@@ -1723,7 +1723,7 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
if(searcher == null)
{
remainingCount = size;
- return;
+ return 0;
}
Hits hits;
try
@@ -1817,7 +1817,9 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
}
}
- remainingCount = count - writer.docCount();
+ int done = writer.docCount();
+ remainingCount = count - done;
+ return done;
}
catch (LuceneIndexException e)
{
@@ -1825,8 +1827,14 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
{
closeDeltaWriter();
}
+ return 0;
}
}
+ else
+ {
+ return 0;
+ }
+
}
catch (LuceneIndexException e)
{
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl2.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl2.java
index 8639fbf790..d0f6038d94 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl2.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl2.java
@@ -1748,7 +1748,7 @@ public class LuceneIndexerImpl2 extends LuceneBase2 implements LuceneIndexer2
return false;
}
- public void updateFullTextSearch(int size) throws LuceneIndexException
+ public int updateFullTextSearch(int size) throws LuceneIndexException
{
checkAbleToDoWork(true, false);
// if (!mainIndexExists())
@@ -1775,7 +1775,7 @@ public class LuceneIndexerImpl2 extends LuceneBase2 implements LuceneIndexer2
if (searcher == null)
{
remainingCount = size;
- return;
+ return 0;
}
Hits hits;
try
@@ -1869,7 +1869,9 @@ public class LuceneIndexerImpl2 extends LuceneBase2 implements LuceneIndexer2
}
}
- remainingCount = count - writer.docCount();
+ int done = writer.docCount();
+ remainingCount = count - done;
+ return done;
}
catch (LuceneIndexException e)
{
@@ -1877,8 +1879,13 @@ public class LuceneIndexerImpl2 extends LuceneBase2 implements LuceneIndexer2
{
closeDeltaWriter();
}
+ return 0;
}
}
+ else
+ {
+ return 0;
+ }
}
catch (IOException e)
{
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java
index 8f2f6d70a4..aa7315956f 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java
@@ -156,7 +156,25 @@ public class LuceneQueryParser extends QueryParser
}
else if (field.equals("TYPE"))
{
- TypeDefinition target = dictionaryService.getType(QName.createQName(queryText));
+ TypeDefinition target;
+ if(queryText.startsWith("{"))
+ {
+ target = dictionaryService.getType(QName.createQName(queryText));
+ }
+ else
+ {
+ int colonPosition = queryText.indexOf(':');
+ if (colonPosition == -1)
+ {
+ // use the default namespace
+ target = dictionaryService.getType(QName.createQName(namespacePrefixResolver.getNamespaceURI(""), queryText));
+ }
+ else
+ {
+ // find the prefix
+ target = dictionaryService.getType(QName.createQName(namespacePrefixResolver.getNamespaceURI(queryText.substring(0, colonPosition)), queryText.substring(colonPosition + 1)));
+ }
+ }
if (target == null)
{
throw new SearcherException("Invalid type: " + queryText);
@@ -186,7 +204,26 @@ public class LuceneQueryParser extends QueryParser
}
else if (field.equals("ASPECT"))
{
- AspectDefinition target = dictionaryService.getAspect(QName.createQName(queryText));
+ AspectDefinition target;
+ if(queryText.startsWith("{"))
+ {
+ target = dictionaryService.getAspect(QName.createQName(queryText));
+ }
+ else
+ {
+ int colonPosition = queryText.indexOf(':');
+ if (colonPosition == -1)
+ {
+ // use the default namespace
+ target = dictionaryService.getAspect(QName.createQName(namespacePrefixResolver.getNamespaceURI(""), queryText));
+ }
+ else
+ {
+ // find the prefix
+ target = dictionaryService.getAspect(QName.createQName(namespacePrefixResolver.getNamespaceURI(queryText.substring(0, colonPosition)), queryText.substring(colonPosition + 1)));
+ }
+ }
+
QName targetQName = target.getName();
HashSet subclasses = new HashSet();
for (QName classRef : dictionaryService.getAllAspects())
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest2.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest2.java
index 92a10d0ea9..d44f13a5ee 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest2.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest2.java
@@ -37,7 +37,9 @@ import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.dictionary.DictionaryDAO;
+import org.alfresco.repo.dictionary.DictionaryNamespaceComponent;
import org.alfresco.repo.dictionary.M2Model;
+import org.alfresco.repo.dictionary.NamespaceDAOImpl;
import org.alfresco.repo.node.BaseNodeServiceTest;
import org.alfresco.repo.search.QueryParameterDefImpl;
import org.alfresco.repo.search.QueryRegisterComponent;
@@ -159,7 +161,7 @@ public class LuceneTest2 extends TestCase
private QueryRegisterComponent queryRegisterComponent;
- private NamespacePrefixResolver namespacePrefixResolver;
+ private DictionaryNamespaceComponent namespacePrefixResolver;
private LuceneIndexerAndSearcher indexerAndSearcher;
@@ -171,6 +173,8 @@ public class LuceneTest2 extends TestCase
private NodeRef[] documentOrder;
+ private NamespaceDAOImpl namespaceDao;
+
public LuceneTest2()
{
super();
@@ -185,10 +189,13 @@ public class LuceneTest2 extends TestCase
luceneFTS = (FullTextSearchIndexer) ctx.getBean("LuceneFullTextSearchIndexer");
contentService = (ContentService) ctx.getBean("contentService");
queryRegisterComponent = (QueryRegisterComponent) ctx.getBean("queryRegisterComponent");
- namespacePrefixResolver = (NamespacePrefixResolver) ctx.getBean("namespaceService");
+ namespacePrefixResolver = (DictionaryNamespaceComponent) ctx.getBean("namespaceService");
indexerAndSearcher = (LuceneIndexerAndSearcher) ctx.getBean("luceneIndexerAndSearcherFactory");
transactionService = (TransactionService) ctx.getBean("transactionComponent");
serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
+
+ namespaceDao = (NamespaceDAOImpl) ctx.getBean("namespaceDAO");
+
this.authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
@@ -208,7 +215,9 @@ public class LuceneTest2 extends TestCase
assertNotNull(modelStream);
M2Model model = M2Model.createModel(modelStream);
dictionaryDAO.putModel(model);
-
+
+ namespaceDao.addPrefix("test", TEST_NAMESPACE);
+
StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
rootNodeRef = nodeService.getRootNode(storeRef);
@@ -1861,19 +1870,39 @@ public class LuceneTest2 extends TestCase
null);
assertEquals(1, results.length());
results.close();
+
+ results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "TYPE:\"" + testType.toPrefixString(namespacePrefixResolver) + "\"", null,
+ null);
+ assertEquals(1, results.length());
+ results.close();
results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "TYPE:\"" + testSuperType.toString() + "\"",
null, null);
assertEquals(13, results.length());
results.close();
+
+ results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "TYPE:\"" + testSuperType.toPrefixString(namespacePrefixResolver) + "\"",
+ null, null);
+ assertEquals(13, results.length());
+ results.close();
results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "ASPECT:\""
- + ISO9075.getXPathName(testAspect) + "\"", null, null);
+ + testAspect.toString() + "\"", null, null);
+ assertEquals(1, results.length());
+ results.close();
+
+ results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "ASPECT:\""
+ + testAspect.toPrefixString(namespacePrefixResolver) + "\"", null, null);
assertEquals(1, results.length());
results.close();
results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "ASPECT:\""
- + ISO9075.getXPathName(testSuperAspect) + "\"", null, null);
+ + testAspect.toString() + "\"", null, null);
+ assertEquals(1, results.length());
+ results.close();
+
+ results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "ASPECT:\""
+ + testAspect.toPrefixString(namespacePrefixResolver) + "\"", null, null);
assertEquals(1, results.length());
results.close();
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardAnalyser.java b/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardAnalyser.java
new file mode 100644
index 0000000000..2f67d5567c
--- /dev/null
+++ b/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardAnalyser.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+package org.alfresco.repo.search.impl.lucene.analysis;
+
+import java.io.Reader;
+import java.util.Set;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.LowerCaseFilter;
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.analysis.StopFilter;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.standard.StandardFilter;
+import org.apache.lucene.analysis.standard.StandardTokenizer;
+
+
+public class AlfrescoStandardAnalyser extends Analyzer
+{
+ private Set stopSet;
+
+ /**
+ * An array containing some common English words that are usually not useful for searching.
+ */
+ public static final String[] STOP_WORDS = StopAnalyzer.ENGLISH_STOP_WORDS;
+
+ /** Builds an analyzer. */
+ public AlfrescoStandardAnalyser()
+ {
+ this(STOP_WORDS);
+ }
+
+ /** Builds an analyzer with the given stop words. */
+ public AlfrescoStandardAnalyser(String[] stopWords)
+ {
+ stopSet = StopFilter.makeStopSet(stopWords);
+ }
+
+ /**
+ * Constructs a {@link StandardTokenizer} filtered by a {@link StandardFilter}, a {@link LowerCaseFilter} and a {@link StopFilter}.
+ */
+ public TokenStream tokenStream(String fieldName, Reader reader)
+ {
+ TokenStream result = new StandardTokenizer(reader);
+ result = new AlfrescoStandardFilter(result);
+ result = new LowerCaseFilter(result);
+ result = new StopFilter(result, stopSet);
+ return result;
+ }
+}
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardFilter.java b/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardFilter.java
new file mode 100644
index 0000000000..6006e4442c
--- /dev/null
+++ b/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardFilter.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+package org.alfresco.repo.search.impl.lucene.analysis;
+
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Stack;
+import java.util.StringTokenizer;
+
+import org.apache.lucene.analysis.TokenFilter;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.standard.StandardTokenizerConstants;
+
+public class AlfrescoStandardFilter extends TokenFilter implements StandardTokenizerConstants
+{
+
+ /** Construct filtering in. */
+ public AlfrescoStandardFilter(TokenStream in)
+ {
+ super(in);
+ }
+
+ private static final String APOSTROPHE_TYPE = tokenImage[APOSTROPHE];
+
+ private static final String ACRONYM_TYPE = tokenImage[ACRONYM];
+
+ private static final String HOST_TYPE = tokenImage[HOST];
+
+ private static final String ALPHANUM_TYPE = tokenImage[ALPHANUM];
+
+ private Queue hostTokens = null;
+
+ /**
+ * Returns the next token in the stream, or null at EOS.
+ *
+ * Removes 's from the end of words.
+ *
+ * Removes dots from acronyms.
+ *
+ * Splits host names ...
+ */
+ public final org.apache.lucene.analysis.Token next() throws java.io.IOException
+ {
+ if (hostTokens == null)
+ {
+ org.apache.lucene.analysis.Token t = input.next();
+
+ if (t == null)
+ return null;
+
+ String text = t.termText();
+ String type = t.type();
+
+ if (type == APOSTROPHE_TYPE && // remove 's
+ (text.endsWith("'s") || text.endsWith("'S")))
+ {
+ return new org.apache.lucene.analysis.Token(text.substring(0, text.length() - 2), t.startOffset(), t
+ .endOffset(), type);
+
+ }
+ else if (type == ACRONYM_TYPE)
+ { // remove dots
+ StringBuffer trimmed = new StringBuffer();
+ for (int i = 0; i < text.length(); i++)
+ {
+ char c = text.charAt(i);
+ if (c != '.')
+ trimmed.append(c);
+ }
+ return new org.apache.lucene.analysis.Token(trimmed.toString(), t.startOffset(), t.endOffset(), type);
+
+ }
+ else if (type == HOST_TYPE)
+ {
+ // ("." )+ >
+ // There must be at least two tokens ....
+ hostTokens = new LinkedList();
+ StringTokenizer tokeniser = new StringTokenizer(text, ".");
+ int start = t.startOffset();
+ int end;
+ while (tokeniser.hasMoreTokens())
+ {
+ String token = tokeniser.nextToken();
+ end = start + token.length();
+ hostTokens.offer(new org.apache.lucene.analysis.Token(token, start, end, ALPHANUM_TYPE));
+ start = end + 1;
+ }
+ // check if we have an acronym ..... yes a.b.c ends up here ...
+
+ if (text.length() == hostTokens.size() * 2 - 1)
+ {
+ hostTokens = null;
+ // acronym
+ StringBuffer trimmed = new StringBuffer();
+ for (int i = 0; i < text.length(); i++)
+ {
+ char c = text.charAt(i);
+ if (c != '.')
+ trimmed.append(c);
+ }
+ return new org.apache.lucene.analysis.Token(trimmed.toString(), t.startOffset(), t.endOffset(),
+ ALPHANUM_TYPE);
+ }
+ else
+ {
+ return hostTokens.remove();
+ }
+ }
+ else
+ {
+ return t;
+ }
+ }
+ else
+ {
+ org.apache.lucene.analysis.Token token = hostTokens.remove();
+ if (hostTokens.isEmpty())
+ {
+ hostTokens = null;
+ }
+ return token;
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/fts/FullTextSearchIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/fts/FullTextSearchIndexerImpl.java
index def19125b7..edce57ef06 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/fts/FullTextSearchIndexerImpl.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/fts/FullTextSearchIndexerImpl.java
@@ -31,7 +31,8 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearchIndexer
{
- private enum State {
+ private enum State
+ {
ACTIVE, PAUSING, PAUSED
};
@@ -48,7 +49,7 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc
public FullTextSearchIndexerImpl()
{
super();
- //System.out.println("Created id is "+this);
+ // System.out.println("Created id is "+this);
}
/*
@@ -64,8 +65,7 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc
/*
* (non-Javadoc)
*
- * @see org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer#indexCompleted(org.alfresco.repo.ref.StoreRef,
- * int, java.lang.Exception)
+ * @see org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer#indexCompleted(org.alfresco.repo.ref.StoreRef, int, java.lang.Exception)
*/
public synchronized void indexCompleted(StoreRef storeRef, int remaining, Exception e)
{
@@ -83,7 +83,7 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc
}
finally
{
- //System.out.println("..Index Complete: id is "+this);
+ // System.out.println("..Index Complete: id is "+this);
this.notifyAll();
}
}
@@ -96,19 +96,19 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc
public synchronized void pause() throws InterruptedException
{
pauseCount++;
- //System.out.println("..Waiting "+pauseCount+" id is "+this);
+ // System.out.println("..Waiting "+pauseCount+" id is "+this);
while ((indexing.size() > 0))
{
- //System.out.println("Pause: Waiting with count of "+indexing.size()+" id is "+this);
+ // System.out.println("Pause: Waiting with count of "+indexing.size()+" id is "+this);
this.wait();
}
pauseCount--;
- if(pauseCount == 0)
+ if (pauseCount == 0)
{
paused = true;
this.notifyAll(); // only resumers
}
- //System.out.println("..Remaining "+pauseCount +" paused = "+paused+" id is "+this);
+ // System.out.println("..Remaining "+pauseCount +" paused = "+paused+" id is "+this);
}
/*
@@ -118,16 +118,16 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc
*/
public synchronized void resume() throws InterruptedException
{
- if(pauseCount == 0)
+ if (pauseCount == 0)
{
- //System.out.println("Direct resume"+" id is "+this);
+ // System.out.println("Direct resume"+" id is "+this);
paused = false;
}
- else
+ else
{
- while(pauseCount > 0)
+ while (pauseCount > 0)
{
- //System.out.println("Reusme waiting on "+pauseCount+" id is "+this);
+ // System.out.println("Reusme waiting on "+pauseCount+" id is "+this);
this.wait();
}
paused = false;
@@ -136,13 +136,13 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc
private synchronized boolean isPaused() throws InterruptedException
{
- if(pauseCount == 0)
+ if (pauseCount == 0)
{
- return paused;
+ return paused;
}
- else
+ else
{
- while(pauseCount > 0)
+ while (pauseCount > 0)
{
this.wait();
}
@@ -160,17 +160,22 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc
// Use the calling thread to index
// Parallel indexing via multiple Quartz thread initiating indexing
- StoreRef toIndex = getNextRef();
- if (toIndex != null)
+ int done = 0;
+ while (done == 0)
{
- //System.out.println("Indexing "+toIndex+" at "+(new java.util.Date()));
- IndexerSPI indexer = luceneIndexerAndSearcherFactory.getIndexer(toIndex);
- indexer.registerCallBack(this);
- indexer.updateFullTextSearch(1000);
- }
- else
- {
- //System.out.println("Nothing to Indexing at "+(new java.util.Date()));
+ StoreRef toIndex = getNextRef();
+ if (toIndex != null)
+ {
+ // System.out.println("Indexing "+toIndex+" at "+(new java.util.Date()));
+ IndexerSPI indexer = luceneIndexerAndSearcherFactory.getIndexer(toIndex);
+ indexer.registerCallBack(this);
+ done += indexer.updateFullTextSearch(1000);
+ }
+ else
+ {
+ break;
+ // System.out.println("Nothing to Indexing at "+(new java.util.Date()));
+ }
}
}
@@ -178,7 +183,7 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc
{
if (paused || (pauseCount > 0))
{
- //System.out.println("Indexing suspended"+" id is "+this);
+ // System.out.println("Indexing suspended"+" id is "+this);
return null;
}
@@ -189,6 +194,8 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc
if (!indexing.contains(ref))
{
nextStoreRef = ref;
+ // FIFO
+ break;
}
}
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java
index 0408317939..d049131c30 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java
@@ -52,7 +52,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.GUID;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
@@ -306,7 +306,7 @@ public class IndexInfo
IndexWriter writer;
try
{
- writer = new IndexWriter(oldIndex, new StandardAnalyzer(), false);
+ writer = new IndexWriter(oldIndex, new AlfrescoStandardAnalyser(), false);
writer.setUseCompoundFile(writerUseCompoundFile);
writer.minMergeDocs = writerMinMergeDocs;
writer.mergeFactor = writerMergeFactor;
@@ -442,7 +442,7 @@ public class IndexInfo
IndexWriter writer;
try
{
- writer = new IndexWriter(emptyIndex, new StandardAnalyzer(), true);
+ writer = new IndexWriter(emptyIndex, new AlfrescoStandardAnalyser(), true);
writer.setUseCompoundFile(writerUseCompoundFile);
writer.minMergeDocs = writerMinMergeDocs;
writer.mergeFactor = writerMergeFactor;
@@ -2424,11 +2424,11 @@ public class IndexInfo
if (docCount < maxDocsForInMemoryMerge)
{
ramDirectory = new RAMDirectory();
- writer = new IndexWriter(ramDirectory, new StandardAnalyzer(), true);
+ writer = new IndexWriter(ramDirectory, new AlfrescoStandardAnalyser(), true);
}
else
{
- writer = new IndexWriter(location, new StandardAnalyzer(), true);
+ writer = new IndexWriter(location, new AlfrescoStandardAnalyser(), true);
}
writer.setUseCompoundFile(mergerUseCompoundFile);
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfoTest.java b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfoTest.java
index 3770a4f39e..7f48f2748a 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfoTest.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfoTest.java
@@ -25,7 +25,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.util.GUID;
import org.alfresco.util.TempFileProvider;
-import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
@@ -95,7 +95,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", "
String guid = GUID.generate();
ii.setStatus(guid, TransactionStatus.ACTIVE, null, null);
- IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer());
+ IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser());
Document doc = new Document();
for (int k = 0; k < 15; k++)
@@ -193,7 +193,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", "
String guid = GUID.generate();
ii.setStatus(guid, TransactionStatus.ACTIVE, null, null);
- IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer());
+ IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser());
Document doc = new Document();
for (int k = 0; k < 15; k++)
@@ -383,7 +383,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", "
String guid = GUID.generate();
ii.setStatus(guid, TransactionStatus.ACTIVE, null, null);
- IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer());
+ IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser());
Document doc = new Document();
for (int k = 0; k < 15; k++)
@@ -469,7 +469,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", "
String guid = GUID.generate();
ii.setStatus(guid, TransactionStatus.ACTIVE, null, null);
- IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer());
+ IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser());
Document doc = new Document();
for (int k = 0; k < 15; k++)
@@ -649,7 +649,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", "
String guid = GUID.generate();
ii.setStatus(guid, TransactionStatus.ACTIVE, null, null);
- IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer());
+ IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser());
Document doc = new Document();
for (int k = 0; k < 15; k++)
@@ -740,7 +740,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", "
String guid = GUID.generate();
ii.setStatus(guid, TransactionStatus.ACTIVE, null, null);
- IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer());
+ IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser());
Document doc = new Document();
for (int k = 0; k < 15; k++)
diff --git a/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java b/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java
index 553c548ec2..c30669cc67 100644
--- a/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java
+++ b/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java
@@ -25,219 +25,359 @@ import org.alfresco.error.AlfrescoRuntimeException;
import org.springframework.dao.DataAccessException;
/**
- * An authority DAO that has no implementation and should not be called.
+ * An authority DAO that has no implementation.
+ *
+ * By default it will throw an exception if any method is called.
+ *
+ * Any of the getter/setter methods can be enabled with a no action implementation.
+ *
+ * This can support deleting users via the UI for LDAP and NTLM. The Alfresco person object is deleted from the UI.
+ * The call to delete the user will return with no action.
+ *
+ * The following methods will always fail.
+ *
+ * getMD4HashedPassword(String userName)
+ * loadUserByUsername(String arg0)
+ * getSalt(UserDetails user)
*
* @author Andy Hind
*/
public class DefaultMutableAuthenticationDao implements MutableAuthenticationDao
{
-
+ private boolean allowCreateUser = false;
+
+ private boolean allowUpdateUser = false;
+
+ private boolean allowDeleteUser = false;
+
+ private boolean allowSetEnabled = false;
+
+ private boolean allowGetEnabled = false;
+
+ private boolean allowSetAccountExpires = false;
+
+ private boolean allowGetAccountHasExpired = false;
+
+ private boolean allowSetCredentialsExpire = false;
+
+ private boolean allowGetCredentialsExpire = false;
+
+ private boolean allowGetCredentialsHaveExpired = false;
+
+ private boolean allowSetAccountLocked = false;
+
+ private boolean allowGetAccountLocked = false;
+
+ private boolean allowSetAccountExpiryDate = false;
+
+ private boolean allowGetAccountExpiryDate = false;
+
+ private boolean allowSetCredentialsExpiryDate = false;
+
+ private boolean allowGetCredentialsExpiryDate = false;
/**
* Create a user with the given userName and password
*
+ * If enabled does nothing.
+ *
* @param userName
* @param rawPassword
* @throws AuthenticationException
*/
public void createUser(String userName, char[] rawPassword) throws AuthenticationException
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowCreateUser)
+ {
+ throw new AlfrescoRuntimeException("Create User is not supported");
+ }
}
-
+
/**
* Update a user's password.
*
+ * If enabled does nothing.
+ *
* @param userName
* @param rawPassword
* @throws AuthenticationException
*/
public void updateUser(String userName, char[] rawPassword) throws AuthenticationException
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowUpdateUser)
+ {
+ throw new AlfrescoRuntimeException("Update user is not supported");
+ }
}
-
+
/**
* Delete a user.
*
+ * If enabled does nothing.
+ *
* @param userName
* @throws AuthenticationException
*/
public void deleteUser(String userName) throws AuthenticationException
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowDeleteUser)
+ {
+ throw new AlfrescoRuntimeException("Delete user is not supported");
+ }
}
-
+
/**
* Check is a user exists.
*
+ * If enabled returns true.
+ *
* @param userName
* @return
*/
public boolean userExists(String userName)
{
+ // All users may exist
return true;
}
-
+
/**
* Enable/disable a user.
*
+ * If enabled does nothing.
+ *
* @param userName
* @param enabled
*/
public void setEnabled(String userName, boolean enabled)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowSetEnabled)
+ {
+ throw new AlfrescoRuntimeException("Set enabled is not supported");
+ }
}
-
+
/**
* Getter for user enabled
*
+ * If enabled returns true.
+ *
* @param userName
* @return
*/
public boolean getEnabled(String userName)
{
- throw new AlfrescoRuntimeException("Not implemented");
-
+ if (!allowGetEnabled)
+ {
+ throw new AlfrescoRuntimeException("Get enabled is not supported");
+ }
+ return true;
}
-
+
/**
* Set if the account should expire
*
+ * If enabled does nothing.
+ *
* @param userName
* @param expires
*/
public void setAccountExpires(String userName, boolean expires)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowSetAccountExpires)
+ {
+ throw new AlfrescoRuntimeException("Set account expires is not supported");
+ }
}
-
+
/**
* Does the account expire?
*
+ * If enabled returns false.
+ *
* @param userName
* @return
*/
-
+
public boolean getAccountExpires(String userName)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowSetAccountExpires)
+ {
+ throw new AlfrescoRuntimeException("Get account expires is not supported");
+ }
+ return false;
}
-
+
/**
* Has the account expired?
*
+ * If enabled returns false.
+ *
* @param userName
* @return
*/
public boolean getAccountHasExpired(String userName)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowGetAccountHasExpired)
+ {
+ throw new AlfrescoRuntimeException("Get account has expired is not supported");
+ }
+ return false;
}
-
+
/**
* Set if the password expires.
*
+ * If enabled does nothing.
+ *
* @param userName
* @param expires
*/
public void setCredentialsExpire(String userName, boolean expires)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowSetCredentialsExpire)
+ {
+ throw new AlfrescoRuntimeException("Set credentials expire is not supported");
+ }
}
-
+
/**
* Do the credentials for the user expire?
*
+ * If enabled returns false.
+ *
* @param userName
* @return
*/
public boolean getCredentialsExpire(String userName)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowGetCredentialsExpire)
+ {
+ throw new AlfrescoRuntimeException("Get credentials expire is not supported");
+ }
+ return false;
}
-
+
/**
* Have the credentials for the user expired?
*
+ * If enabled returns false.
+ *
* @param userName
* @return
*/
public boolean getCredentialsHaveExpired(String userName)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowGetCredentialsHaveExpired)
+ {
+ throw new AlfrescoRuntimeException("Get credentials have expired is not supported");
+ }
+ return false;
}
-
+
/**
* Set if the account is locked.
*
+ * If enabled does nothing.
+ *
* @param userName
* @param locked
*/
public void setLocked(String userName, boolean locked)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowSetAccountLocked)
+ {
+ throw new AlfrescoRuntimeException("Set account locked is not supported");
+ }
}
-
+
/**
* Is the account locked?
*
+ * If enabled returns false.
+ *
* @param userName
* @return
*/
public boolean getAccountlocked(String userName)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowGetAccountLocked)
+ {
+ throw new AlfrescoRuntimeException("Get account locked is not supported");
+ }
+ return false;
}
-
+
/**
* Set the date on which the account expires
*
+ * If enabled does nothing.
+ *
* @param userName
* @param exipryDate
*/
public void setAccountExpiryDate(String userName, Date exipryDate)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowSetAccountExpiryDate)
+ {
+ throw new AlfrescoRuntimeException("Set account expiry date is not supported");
+ }
}
-
- /**
+
+ /**
* Get the date when this account expires.
*
+ * If enabled returns null.
+ *
* @param userName
* @return
*/
public Date getAccountExpiryDate(String userName)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowGetAccountExpiryDate)
+ {
+ throw new AlfrescoRuntimeException("Get account expiry date is not supported");
+ }
+ return null;
}
-
+
/**
* Set the date when credentials expire.
*
+ * If enabled does nothing.
+ *
* @param userName
* @param exipryDate
*/
public void setCredentialsExpiryDate(String userName, Date exipryDate)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowSetCredentialsExpiryDate)
+ {
+ throw new AlfrescoRuntimeException("Set credentials expiry date is not supported");
+ }
}
-
+
/**
* Get the date when the credentials/password expire.
*
+ * If enabled returns null.
+ *
* @param userName
* @return
*/
public Date getCredentialsExpiryDate(String userName)
{
- throw new AlfrescoRuntimeException("Not implemented");
+ if (!allowGetCredentialsExpiryDate)
+ {
+ throw new AlfrescoRuntimeException("Get credentials expiry date is not supported");
+ }
+ return null;
}
-
+
/**
* Get the MD4 password hash
*
+ * Always throws an exception.
+ *
* @param userName
* @return
*/
@@ -249,7 +389,10 @@ public class DefaultMutableAuthenticationDao implements MutableAuthenticationDao
/**
* Return the user details for the specified user
*
- * @param user String
+ * Always throws an exception.
+ *
+ * @param user
+ * String
* @return UserDetails
* @exception UsernameNotFoundException
* @exception DataAccessException
@@ -262,11 +405,99 @@ public class DefaultMutableAuthenticationDao implements MutableAuthenticationDao
/**
* Return salt for user
*
- * @param user UserDetails
+ * Always throws an exception.
+ *
+ * @param user
+ * UserDetails
* @return Object
*/
public Object getSalt(UserDetails user)
{
throw new AlfrescoRuntimeException("Not implemented");
}
+
+
+ // -------- //
+ // Bean IOC //
+ // -------- //
+
+ public void setAllowCreateUser(boolean allowCreateUser)
+ {
+ this.allowCreateUser = allowCreateUser;
+ }
+
+ public void setAllowDeleteUser(boolean allowDeleteUser)
+ {
+ this.allowDeleteUser = allowDeleteUser;
+ }
+
+ public void setAllowGetAccountExpiryDate(boolean allowGetAccountExpiryDate)
+ {
+ this.allowGetAccountExpiryDate = allowGetAccountExpiryDate;
+ }
+
+ public void setAllowGetAccountHasExpired(boolean allowGetAccountHasExpired)
+ {
+ this.allowGetAccountHasExpired = allowGetAccountHasExpired;
+ }
+
+ public void setAllowGetAccountLocked(boolean allowGetAccountLocked)
+ {
+ this.allowGetAccountLocked = allowGetAccountLocked;
+ }
+
+ public void setAllowGetCredentialsExpire(boolean allowGetCredentialsExpire)
+ {
+ this.allowGetCredentialsExpire = allowGetCredentialsExpire;
+ }
+
+ public void setAllowGetCredentialsExpiryDate(boolean allowGetCredentialsExpiryDate)
+ {
+ this.allowGetCredentialsExpiryDate = allowGetCredentialsExpiryDate;
+ }
+
+ public void setAllowGetCredentialsHaveExpired(boolean allowGetCredentialsHaveExpired)
+ {
+ this.allowGetCredentialsHaveExpired = allowGetCredentialsHaveExpired;
+ }
+
+ public void setAllowGetEnabled(boolean allowGetEnabled)
+ {
+ this.allowGetEnabled = allowGetEnabled;
+ }
+
+ public void setAllowSetAccountExpires(boolean allowSetAccountExpires)
+ {
+ this.allowSetAccountExpires = allowSetAccountExpires;
+ }
+
+ public void setAllowSetAccountExpiryDate(boolean allowSetAccountExpiryDate)
+ {
+ this.allowSetAccountExpiryDate = allowSetAccountExpiryDate;
+ }
+
+ public void setAllowSetAccountLocked(boolean allowSetAccountLocked)
+ {
+ this.allowSetAccountLocked = allowSetAccountLocked;
+ }
+
+ public void setAllowSetCredentialsExpire(boolean allowSetCredentialsExpire)
+ {
+ this.allowSetCredentialsExpire = allowSetCredentialsExpire;
+ }
+
+ public void setAllowSetCredentialsExpiryDate(boolean allowSetCredentialsExpiryDate)
+ {
+ this.allowSetCredentialsExpiryDate = allowSetCredentialsExpiryDate;
+ }
+
+ public void setAllowSetEnabled(boolean allowSetEnabled)
+ {
+ this.allowSetEnabled = allowSetEnabled;
+ }
+
+ public void setAllowUpdateUser(boolean allowUpdateUser)
+ {
+ this.allowUpdateUser = allowUpdateUser;
+ }
}
diff --git a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPGroupExportSource.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPGroupExportSource.java
index 07a6ba87fd..171dc4f4c0 100644
--- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPGroupExportSource.java
+++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPGroupExportSource.java
@@ -91,6 +91,10 @@ public class LDAPGroupExportSource implements ExportSource, InitializingBean
private AuthorityDAO authorityDAO;
+ private boolean errorOnMissingGID;
+
+ private boolean errorOnMissingUID;
+
public LDAPGroupExportSource()
{
super();
@@ -146,6 +150,16 @@ public class LDAPGroupExportSource implements ExportSource, InitializingBean
this.errorOnMissingMembers = errorOnMissingMembers;
}
+ public void setErrorOnMissingGID(boolean errorOnMissingGID)
+ {
+ this.errorOnMissingGID = errorOnMissingGID;
+ }
+
+ public void setErrorOnMissingUID(boolean errorOnMissingUID)
+ {
+ this.errorOnMissingUID = errorOnMissingUID;
+ }
+
public void setAuthorityDAO(AuthorityDAO authorityDAO)
{
this.authorityDAO = authorityDAO;
@@ -279,7 +293,7 @@ public class LDAPGroupExportSource implements ExportSource, InitializingBean
ContentModel.TYPE_AUTHORITY_CONTAINER.getLocalName(), ContentModel.TYPE_AUTHORITY_CONTAINER
.toPrefixString(namespaceService), attrs);
- if ((authorityDAO != null ) && authorityDAO.authorityExists(group.gid))
+ if ((authorityDAO != null) && authorityDAO.authorityExists(group.gid))
{
NodeRef authNodeRef = authorityDAO.getAuthorityNodeRefOrNull(group.gid);
if (authNodeRef != null)
@@ -295,7 +309,7 @@ public class LDAPGroupExportSource implements ExportSource, InitializingBean
.toPrefixString(namespaceService));
}
}
-
+
writer.startElement(ContentModel.PROP_AUTHORITY_NAME.getNamespaceURI(), ContentModel.PROP_AUTHORITY_NAME
.getLocalName(), ContentModel.PROP_AUTHORITY_NAME.toPrefixString(namespaceService),
new AttributesImpl());
@@ -368,8 +382,17 @@ public class LDAPGroupExportSource implements ExportSource, InitializingBean
Attribute gidAttribute = attributes.get(groupIdAttributeName);
if (gidAttribute == null)
{
- throw new ExportSourceImporterException(
- "Group returned by group search does not have mandatory group id attribute " + attributes);
+ if (errorOnMissingGID)
+ {
+ throw new ExportSourceImporterException(
+ "Group returned by group search does not have mandatory group id attribute "
+ + attributes);
+ }
+ else
+ {
+ s_logger.warn("Missing GID on " + attributes);
+ continue;
+ }
}
String gid = (String) gidAttribute.get(0);
@@ -453,7 +476,15 @@ public class LDAPGroupExportSource implements ExportSource, InitializingBean
Attribute objectclass = attributes.get("objectclass");
if (objectclass == null)
{
- throw new ExportSourceImporterException("Failed to find attribute objectclass for DN " + dn);
+ if (errorOnMissingMembers)
+ {
+ throw new ExportSourceImporterException("Failed to find attribute objectclass for DN "
+ + dn);
+ }
+ else
+ {
+ continue;
+ }
}
for (int i = 0; i < objectclass.size(); i++)
{
@@ -479,8 +510,18 @@ public class LDAPGroupExportSource implements ExportSource, InitializingBean
Attribute groupIdAttribute = attributes.get(groupIdAttributeName);
if (groupIdAttribute == null)
{
- throw new ExportSourceImporterException("Group missing group id attribute DN ="
- + dn + " att = " + groupIdAttributeName);
+ if (errorOnMissingGID)
+ {
+ throw new ExportSourceImporterException(
+ "Group missing group id attribute DN ="
+ + dn + " att = " + groupIdAttributeName);
+ }
+ else
+ {
+ s_logger.warn("Group missing group id attribute DN ="
+ + dn + " att = " + groupIdAttributeName);
+ continue;
+ }
}
id = (String) groupIdAttribute.get(0);
}
@@ -504,8 +545,18 @@ public class LDAPGroupExportSource implements ExportSource, InitializingBean
Attribute userIdAttribute = attributes.get(userIdAttributeName);
if (userIdAttribute == null)
{
- throw new ExportSourceImporterException("User missing user id attribute DN ="
- + dn + " att = " + userIdAttributeName);
+ if (errorOnMissingUID)
+ {
+ throw new ExportSourceImporterException(
+ "User missing user id attribute DN ="
+ + dn + " att = " + userIdAttributeName);
+ }
+ else
+ {
+ s_logger.warn("User missing user id attribute DN ="
+ + dn + " att = " + userIdAttributeName);
+ continue;
+ }
}
id = (String) userIdAttribute.get(0);
}
@@ -527,7 +578,14 @@ public class LDAPGroupExportSource implements ExportSource, InitializingBean
{
if (isGroup == null)
{
- throw new ExportSourceImporterException("Type not recognised for DN" + dn);
+ if (errorOnMissingMembers)
+ {
+ throw new ExportSourceImporterException("Type not recognised for DN" + dn);
+ }
+ else
+ {
+ continue;
+ }
}
else if (isGroup)
{
@@ -538,7 +596,14 @@ public class LDAPGroupExportSource implements ExportSource, InitializingBean
Group child = lookup.get("GROUP_" + id);
if (child == null)
{
+ if (errorOnMissingMembers)
+ {
throw new ExportSourceImporterException("Failed to find child group " + id);
+ }
+ else
+ {
+ continue;
+ }
}
if (rootGroups.contains(child))
{
@@ -688,7 +753,7 @@ public class LDAPGroupExportSource implements ExportSource, InitializingBean
TransactionService txs = (TransactionService) ctx.getBean("transactionComponent");
UserTransaction tx = txs.getUserTransaction();
tx.begin();
-
+
File file = new File(args[0]);
Writer writer = new BufferedWriter(new FileWriter(file));
XMLWriter xmlWriter = createXMLExporter(writer);
diff --git a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
index af6c4612de..302ea2f178 100644
--- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
@@ -30,17 +30,22 @@ import javax.naming.directory.InitialDirContext;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.util.ApplicationContextHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
-public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFactory
+public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFactory, InitializingBean
{
+ private static final Log logger = LogFactory.getLog(LDAPInitialDirContextFactoryImpl.class);
+
private Map initialDirContextEnvironment = Collections. emptyMap();
static
{
System.setProperty("javax.security.auth.useSubjectCredentialsOnly", "false");
}
-
+
public LDAPInitialDirContextFactoryImpl()
{
super();
@@ -87,11 +92,22 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
throw new AuthenticationException("Null user name provided.");
}
+
+ if (principal.length() == 0)
+ {
+ throw new AuthenticationException("Empty user name provided.");
+ }
if (credentials == null)
{
throw new AuthenticationException("No credentials provided.");
}
+
+ if (credentials.length() == 0)
+ {
+ throw new AuthenticationException("Empty credentials provided.");
+ }
+
Hashtable env = new Hashtable(initialDirContextEnvironment.size());
env.putAll(initialDirContextEnvironment);
env.put(Context.SECURITY_PRINCIPAL, principal);
@@ -187,4 +203,108 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
}
+ public void afterPropertiesSet() throws Exception
+ {
+ // Check Anonymous bind
+
+ Hashtable env = new Hashtable(initialDirContextEnvironment.size());
+ env.putAll(initialDirContextEnvironment);
+ env.remove(Context.SECURITY_PRINCIPAL);
+ env.remove(Context.SECURITY_CREDENTIALS);
+ try
+ {
+ new InitialDirContext(env);
+
+ logger.warn("LDAP server supports anonymous bind " + env.get(Context.PROVIDER_URL));
+ }
+ catch (javax.naming.AuthenticationException ax)
+ {
+
+ }
+ catch (NamingException nx)
+ {
+ throw new AuthenticationException("Unable to connect to LDAP Server; check LDAP configuration", nx);
+ }
+
+ // Simple DN and password
+
+ env = new Hashtable(initialDirContextEnvironment.size());
+ env.putAll(initialDirContextEnvironment);
+ env.put(Context.SECURITY_PRINCIPAL, "daftAsABrush");
+ env.put(Context.SECURITY_CREDENTIALS, "daftAsABrush");
+ try
+ {
+
+ new InitialDirContext(env);
+
+ throw new AuthenticationException(
+ "The ldap server at "
+ + env.get(Context.PROVIDER_URL)
+ + " falls back to use anonymous bind if invalid security credentials are presented. This is not supported.");
+ }
+ catch (javax.naming.AuthenticationException ax)
+ {
+ logger.info("LDAP server does not fall back to anonymous bind for a string uid and password at " + env.get(Context.PROVIDER_URL));
+ }
+ catch (NamingException nx)
+ {
+ logger.info("LDAP server does not support simple string user ids and invalid credentials at "+ env.get(Context.PROVIDER_URL));
+ }
+
+ // DN and password
+
+ env = new Hashtable(initialDirContextEnvironment.size());
+ env.putAll(initialDirContextEnvironment);
+ env.put(Context.SECURITY_PRINCIPAL, "cn=daftAsABrush,dc=woof");
+ env.put(Context.SECURITY_CREDENTIALS, "daftAsABrush");
+ try
+ {
+
+ new InitialDirContext(env);
+
+ throw new AuthenticationException(
+ "The ldap server at "
+ + env.get(Context.PROVIDER_URL)
+ + " falls back to use anonymous bind if invalid security credentials are presented. This is not supported.");
+ }
+ catch (javax.naming.AuthenticationException ax)
+ {
+ logger.info("LDAP server does not fall back to anonymous bind for a simple dn and password at " + env.get(Context.PROVIDER_URL));
+ }
+ catch (NamingException nx)
+ {
+ logger.info("LDAP server does not support simple DN and invalid password at "+ env.get(Context.PROVIDER_URL));
+ }
+
+ // Check more if we have a real principal we expect to work
+
+ env = new Hashtable(initialDirContextEnvironment.size());
+ env.putAll(initialDirContextEnvironment);
+ if(env.get(Context.SECURITY_PRINCIPAL) != null)
+ {
+ // Correct principal invalid password
+
+ env = new Hashtable(initialDirContextEnvironment.size());
+ env.putAll(initialDirContextEnvironment);
+ env.put(Context.SECURITY_CREDENTIALS, "sdasdasdasdasd123123123");
+ try
+ {
+
+ new InitialDirContext(env);
+
+ throw new AuthenticationException(
+ "The ldap server at "
+ + env.get(Context.PROVIDER_URL)
+ + " falls back to use anonymous bind for a known principal if invalid security credentials are presented. This is not supported.");
+ }
+ catch (javax.naming.AuthenticationException ax)
+ {
+ logger.info("LDAP server does not fall back to anonymous bind for known principal and invalid credentials at " + env.get(Context.PROVIDER_URL));
+ }
+ catch (NamingException nx)
+ {
+ // already donw
+ }
+ }
+ }
}
diff --git a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java
index 422871d5ae..cf383c4dd3 100644
--- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java
+++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java
@@ -67,6 +67,8 @@ public class LDAPPersonExportSource implements ExportSource
private NamespaceService namespaceService;
private String defaultHomeFolder;
+
+ private boolean errorOnMissingUID;
public LDAPPersonExportSource()
{
@@ -113,6 +115,11 @@ public class LDAPPersonExportSource implements ExportSource
this.attributeMapping = attributeMapping;
}
+ public void setErrorOnMissingUID(boolean errorOnMissingUID)
+ {
+ this.errorOnMissingUID = errorOnMissingUID;
+ }
+
public void generateExport(XMLWriter writer)
{
QName nodeUUID = QName.createQName("sys:node-uuid", namespaceService);
@@ -161,8 +168,16 @@ public class LDAPPersonExportSource implements ExportSource
Attribute uidAttribute = attributes.get(userIdAttributeName);
if (uidAttribute == null)
{
+ if(errorOnMissingUID)
+ {
throw new ExportSourceImporterException(
"User returned by user search does not have mandatory user id attribute " + attributes);
+ }
+ else
+ {
+ s_logger.warn("User returned by user search does not have mandatory user id attribute " + attributes);
+ continue;
+ }
}
String uid = (String) uidAttribute.get(0);
diff --git a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java
index db1725cab5..656967357c 100644
--- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java
+++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java
@@ -210,7 +210,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
throw new IllegalArgumentException("Property 'policyComponent' has not been set");
}
- policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onMoveNode"), ContentModel.ASPECT_AUDITABLE, new JavaBehaviour(this, "onMoveNode"));
+ policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onMoveNode"), ContentModel.TYPE_BASE, new JavaBehaviour(this, "onMoveNode"));
}
diff --git a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java
index 4a620b9173..8f2acca924 100644
--- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java
+++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java
@@ -83,6 +83,16 @@ public class PermissionServiceTest extends AbstractPermissionTest
allowAndyReadChildren = new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ_CHILDREN),
"andy", AccessStatus.ALLOWED);
}
+
+ public void testWeSetConsumerOnRootIsNotSupportedByHasPermisssionAsItIsTheWrongType()
+ {
+ runAs("andy");
+ assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size());
+ permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.CONSUMER),
+ "andy", AccessStatus.ALLOWED));
+ assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size());
+ assertEquals(permissionService.hasPermission(rootNodeRef, (PermissionService.CONSUMER)), AccessStatus.DENIED);
+ }
public void testGetAllSetPermissions()
{
@@ -417,7 +427,7 @@ public class PermissionServiceTest extends AbstractPermissionTest
{
Set answer = permissionService.getSettablePermissions(QName.createQName("sys", "base",
namespacePrefixResolver));
- assertEquals(21, answer.size());
+ assertEquals(36, answer.size());
answer = permissionService.getSettablePermissions(QName.createQName("cm", "ownable", namespacePrefixResolver));
assertEquals(0, answer.size());
@@ -427,29 +437,33 @@ public class PermissionServiceTest extends AbstractPermissionTest
answer = permissionService.getSettablePermissions(QName.createQName("cm", "folder", namespacePrefixResolver));
assertEquals(5, answer.size());
+
+ answer = permissionService.getSettablePermissions(QName.createQName("cm", "monkey", namespacePrefixResolver));
+ assertEquals(0, answer.size());
}
+
public void testGetSettablePermissionsForNode()
{
QName ownable = QName.createQName("cm", "ownable", namespacePrefixResolver);
Set answer = permissionService.getSettablePermissions(rootNodeRef);
- assertEquals(25, answer.size());
+ assertEquals(42, answer.size());
nodeService.addAspect(rootNodeRef, ownable, null);
answer = permissionService.getSettablePermissions(rootNodeRef);
- assertEquals(25, answer.size());
+ assertEquals(42, answer.size());
nodeService.removeAspect(rootNodeRef, ownable);
answer = permissionService.getSettablePermissions(rootNodeRef);
- assertEquals(25, answer.size());
+ assertEquals(42, answer.size());
}
public void testSimplePermissionOnRoot()
{
runAs("andy");
- assertEquals(25, permissionService.getPermissions(rootNodeRef).size());
+ assertEquals(42, permissionService.getPermissions(rootNodeRef).size());
assertEquals(0, countGranted(permissionService.getPermissions(rootNodeRef)));
assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size());
@@ -462,8 +476,8 @@ public class PermissionServiceTest extends AbstractPermissionTest
assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size());
runAs("andy");
- assertEquals(25, permissionService.getPermissions(rootNodeRef).size());
- assertEquals(1, countGranted(permissionService.getPermissions(rootNodeRef)));
+ assertEquals(42, permissionService.getPermissions(rootNodeRef).size());
+ assertEquals(2, countGranted(permissionService.getPermissions(rootNodeRef)));
assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED);
runAs("lemur");
@@ -578,8 +592,8 @@ public class PermissionServiceTest extends AbstractPermissionTest
permissionService.setPermission(allowAndyRead);
runAs("andy");
- assertEquals(25, permissionService.getPermissions(rootNodeRef).size());
- assertEquals(4, countGranted(permissionService.getPermissions(rootNodeRef)));
+ assertEquals(42, permissionService.getPermissions(rootNodeRef).size());
+ assertEquals(7, countGranted(permissionService.getPermissions(rootNodeRef)));
assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size());
assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED);
diff --git a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java
index e374595c68..d7c6938916 100644
--- a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java
+++ b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java
@@ -50,11 +50,7 @@ import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.InitializingBean;
/**
- * The implementation of the model DAO
- *
- * Reads and stores the top level model information
- *
- * Encapsulates access to this information
+ * The implementation of the model DAO Reads and stores the top level model information Encapsulates access to this information
*
* @author andyh
*/
@@ -97,16 +93,13 @@ public class PermissionModel implements ModelDAO, InitializingBean
private AccessStatus defaultPermission;
// Cache granting permissions
- private HashMap> grantingPermissions =
- new HashMap>();
+ private HashMap> grantingPermissions = new HashMap>();
// Cache grantees
- private HashMap> granteePermissions =
- new HashMap>();
+ private HashMap> granteePermissions = new HashMap>();
// Cache the mapping of extended groups to the base
- private HashMap groupsToBaseGroup =
- new HashMap();
+ private HashMap groupsToBaseGroup = new HashMap();
private HashMap uniqueMap;
@@ -115,13 +108,13 @@ public class PermissionModel implements ModelDAO, InitializingBean
private HashMap permissionGroupMap;
private HashMap permissionReferenceMap;
-
- private Map> cachedTypePermissionsExposed =
- new HashMap>(128, 1.0f);
-
- private Map> cachedTypePermissionsUnexposed =
- new HashMap>(128, 1.0f);
-
+
+ private Map> cachedTypePermissionsExposed = new HashMap>(
+ 128, 1.0f);
+
+ private Map> cachedTypePermissionsUnexposed = new HashMap>(
+ 128, 1.0f);
+
public PermissionModel()
{
super();
@@ -145,9 +138,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
}
/*
- * Initialise from file
- *
- * (non-Javadoc)
+ * Initialise from file (non-Javadoc)
*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@@ -283,7 +274,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
{
return getAllPermissionsImpl(type, true);
}
-
+
@SuppressWarnings("unchecked")
private Set getAllPermissionsImpl(QName type, boolean exposedOnly)
{
@@ -300,18 +291,22 @@ public class PermissionModel implements ModelDAO, InitializingBean
if (permissions == null)
{
permissions = new LinkedHashSet();
- if (dictionaryService.getClass(type).isAspect())
+ ClassDefinition cd = dictionaryService.getClass(type);
+ if (cd != null)
{
- addAspectPermissions(type, permissions, exposedOnly);
- }
- else
- {
- mergeGeneralAspectPermissions(permissions, exposedOnly);
- addTypePermissions(type, permissions, exposedOnly);
+ if (cd.isAspect())
+ {
+ addAspectPermissions(type, permissions, exposedOnly);
+ }
+ else
+ {
+ mergeGeneralAspectPermissions(permissions, exposedOnly);
+ addTypePermissions(type, permissions, exposedOnly);
+ }
}
cache.put(type, permissions);
}
- return (Set)permissions.clone();
+ return (Set) permissions.clone();
}
/**
@@ -401,10 +396,10 @@ public class PermissionModel implements ModelDAO, InitializingBean
}
}
}
-
+
private void mergeGeneralAspectPermissions(Set target, boolean exposedOnly)
{
- for(QName aspect : dictionaryService.getAllAspects())
+ for (QName aspect : dictionaryService.getAllAspects())
{
mergePermissions(target, aspect, exposedOnly, false);
}
@@ -424,10 +419,10 @@ public class PermissionModel implements ModelDAO, InitializingBean
{
//
// TODO: cache permissions based on type and exposed flag
- // create JMeter test to see before/after effect!
+ // create JMeter test to see before/after effect!
//
QName typeName = nodeService.getType(nodeRef);
-
+
Set permissions = getAllPermissions(typeName);
mergeGeneralAspectPermissions(permissions, exposedOnly);
// Add non mandatory aspects...
@@ -663,9 +658,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
}
/**
- * Query the model for a base permission group
- *
- * Uses the Data Dictionary to reolve inheritance
+ * Query the model for a base permission group Uses the Data Dictionary to reolve inheritance
*
* @param pg
* @return
@@ -775,8 +768,9 @@ public class PermissionModel implements ModelDAO, InitializingBean
{
for (PermissionGroup pg : ps.getPermissionGroups())
{
- if (target.equals(getBasePermissionGroupOrNull(pg))
- && isPartOfDynamicPermissionGroup(pg, qName, aspectQNames))
+ PermissionGroup base = getBasePermissionGroupOrNull(pg);
+ if (target.equals(base)
+ && (!base.isTypeRequired() || isPartOfDynamicPermissionGroup(pg, qName, aspectQNames)))
{
// Add includes
for (PermissionReference pr : pg.getIncludedPermissionGroups())
@@ -791,7 +785,8 @@ public class PermissionModel implements ModelDAO, InitializingBean
for (PermissionReference grantedTo : p.getGrantedToGroups())
{
PermissionGroup base = getBasePermissionGroupOrNull(getPermissionGroupOrNull(grantedTo));
- if (target.equals(base) && (!base.isTypeRequired() || isPartOfDynamicPermissionGroup(grantedTo, qName, aspectQNames)))
+ if (target.equals(base)
+ && (!base.isTypeRequired() || isPartOfDynamicPermissionGroup(grantedTo, qName, aspectQNames)))
{
if (on == RequiredPermission.On.NODE)
{
@@ -887,7 +882,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
public PermissionReference getPermissionReference(QName qname, String permissionName)
{
- if(permissionName == null)
+ if (permissionName == null)
{
return null;
}
@@ -963,7 +958,8 @@ public class PermissionModel implements ModelDAO, InitializingBean
+ PermissionService.ALL_PERMISSIONS);
}
uniqueMap.put(PermissionService.ALL_PERMISSIONS, new SimplePermissionReference(QName.createQName(
- NamespaceService.SECURITY_MODEL_1_0_URI, PermissionService.ALL_PERMISSIONS), PermissionService.ALL_PERMISSIONS));
+ NamespaceService.SECURITY_MODEL_1_0_URI, PermissionService.ALL_PERMISSIONS),
+ PermissionService.ALL_PERMISSIONS));
}
diff --git a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java
index 861d8678eb..758e3d94d7 100644
--- a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java
+++ b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java
@@ -22,6 +22,7 @@ import org.alfresco.repo.security.permissions.PermissionEntry;
import org.alfresco.repo.security.permissions.PermissionReference;
import org.alfresco.repo.security.permissions.impl.AbstractPermissionTest;
import org.alfresco.repo.security.permissions.impl.SimplePermissionReference;
+import org.alfresco.repo.security.permissions.impl.RequiredPermission.On;
import org.alfresco.service.namespace.QName;
public class PermissionModelTest extends AbstractPermissionTest
@@ -32,12 +33,21 @@ public class PermissionModelTest extends AbstractPermissionTest
super();
}
+ public void testWoof()
+ {
+ QName typeQname = nodeService.getType(rootNodeRef);
+ Set aspectQNames = nodeService.getAspects(rootNodeRef);
+ PermissionReference ref = permissionModelDAO.getPermissionReference(null, "CheckOut");
+ Set answer = permissionModelDAO.getRequiredPermissions(ref, typeQname, aspectQNames, On.NODE);
+ assertEquals(1, answer.size());
+ }
+
public void testIncludePermissionGroups()
{
Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject",
namespacePrefixResolver), "Consumer"));
- assertEquals(5, grantees.size());
+ assertEquals(8, grantees.size());
}
public void testIncludePermissionGroups2()
@@ -45,7 +55,7 @@ public class PermissionModelTest extends AbstractPermissionTest
Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject",
namespacePrefixResolver), "Contributor"));
- assertEquals(11, grantees.size());
+ assertEquals(17, grantees.size());
}
public void testIncludePermissionGroups3()
@@ -53,7 +63,7 @@ public class PermissionModelTest extends AbstractPermissionTest
Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject",
namespacePrefixResolver), "Editor"));
- assertEquals(11, grantees.size());
+ assertEquals(17, grantees.size());
}
public void testIncludePermissionGroups4()
@@ -61,14 +71,34 @@ public class PermissionModelTest extends AbstractPermissionTest
Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject",
namespacePrefixResolver), "Collaborator"));
- assertEquals(16, grantees.size());
+ assertEquals(24, grantees.size());
+ }
+
+ public void testIncludePermissionGroups5()
+ {
+ Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject",
+ namespacePrefixResolver), "Coordinator"));
+
+ assertEquals(59, grantees.size());
+ }
+
+ public void testIncludePermissionGroups6()
+ {
+ Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject",
+ namespacePrefixResolver), "RecordAdministrator"));
+
+ assertEquals(19, grantees.size());
}
public void testGetGrantingPermissions()
{
Set granters = permissionModelDAO.getGrantingPermissions(new SimplePermissionReference(QName.createQName("sys", "base",
namespacePrefixResolver), "ReadProperties"));
- assertEquals(9, granters.size());
+ assertEquals(10, granters.size());
+
+ granters = permissionModelDAO.getGrantingPermissions(new SimplePermissionReference(QName.createQName("sys", "base",
+ namespacePrefixResolver), "_ReadProperties"));
+ assertEquals(11, granters.size());
}
public void testGlobalPermissions()
@@ -76,4 +106,5 @@ public class PermissionModelTest extends AbstractPermissionTest
Set extends PermissionEntry> globalPermissions = permissionModelDAO.getGlobalPermissionEntries();
assertEquals(5, globalPermissions.size());
}
+
}
diff --git a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java
index c705ca22d2..3bc2971b7d 100644
--- a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java
+++ b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java
@@ -41,6 +41,7 @@ import org.alfresco.service.cmr.search.CategoryService;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.AuthorityService;
+import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.cmr.view.ExporterService;
@@ -331,4 +332,14 @@ public class ServiceDescriptorRegistry
{
return (AuditService)getService(AUDIT_SERVICE);
}
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.ServiceRegistry#getOwnableService()
+ */
+ public OwnableService getOwnableService()
+ {
+ return (OwnableService)getService(OWNABLE_SERVICE);
+ }
+
+
}
diff --git a/source/java/org/alfresco/repo/transaction/TransactionAwareSingleton.java b/source/java/org/alfresco/repo/transaction/TransactionAwareSingleton.java
new file mode 100644
index 0000000000..c383a2fc26
--- /dev/null
+++ b/source/java/org/alfresco/repo/transaction/TransactionAwareSingleton.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2006 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+package org.alfresco.repo.transaction;
+
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+
+/**
+ * A transactionally-safe storage class for singleton objects. Changes to the singleton
+ * are only visibly promoted when the transaction is committed.
+ *
+ *
+ * private static final TransactionAwareSingleton MY_SINGLETON = new TransactionAwareSingleton();
+ *
+ *
+ * All modifications to the singleton via {@link #get()} and {@link #put(T)} are made in a
+ * transaction-local manner and promoted to the shared value in a thread-safe manner upon
+ * transacton completion. Transaction-local changes take precedence over the shared value.
+ *
+ * @see org.alfresco.repo.transaction.AlfrescoTransactionSupport
+ *
+ * @author Derek Hulley
+ */
+public class TransactionAwareSingleton extends TransactionListenerAdapter
+{
+ private static final String TRANSACTION_KEY = "TransactionAwareSingleton.storage";
+
+ private final ReadLock singletonReadLock;
+ private final WriteLock singletonWriteLock;
+ private Object singletonValue;
+
+ public TransactionAwareSingleton()
+ {
+ ReentrantReadWriteLock serverReadWriteLock = new ReentrantReadWriteLock();
+ singletonReadLock = serverReadWriteLock.readLock();
+ singletonWriteLock = serverReadWriteLock.writeLock();
+ }
+
+ private void setValue(Object value)
+ {
+ // get a write lock
+ singletonWriteLock.lock();
+ try
+ {
+ singletonValue = value;
+ }
+ finally
+ {
+ singletonWriteLock.unlock();
+ }
+ }
+
+ private Object getValue()
+ {
+ // get a read lock
+ singletonReadLock.lock();
+ try
+ {
+ return singletonValue;
+ }
+ finally
+ {
+ singletonReadLock.unlock();
+ }
+ }
+
+ /**
+ * @return Returns the transaction- and thread-safe wrapped instance
+ */
+ @SuppressWarnings("unchecked")
+ public T get()
+ {
+ // an in-transaction value overrides the singleton
+ TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(TRANSACTION_KEY);
+ if (storage != null)
+ {
+ return (T) storage.newValue;
+ }
+ else
+ {
+ return (T) getValue();
+ }
+ }
+
+ /**
+ * Store the value in a transaction- and thread-safe manner. It will only be persisted
+ * at the end of the transaction but will be visible to the current transaction from
+ * this call onwards.
+ *
+ * @param value the value to store
+ */
+ public void put(T value)
+ {
+ // the value is changing
+ TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(TRANSACTION_KEY);
+ if (storage == null)
+ {
+ // it has not changed before
+ storage = new TransactionStorage();
+ AlfrescoTransactionSupport.bindResource(TRANSACTION_KEY, storage);
+ // listen to the transaction
+ AlfrescoTransactionSupport.bindListener(this);
+ }
+ storage.newValue = value;
+ }
+
+ /**
+ * Promotes the storage value to the single value, if required
+ */
+ public void afterCommit()
+ {
+ TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(TRANSACTION_KEY);
+ if (storage != null)
+ {
+ // the value was overridden
+ setValue(storage.newValue);
+ }
+ }
+
+ /**
+ * In-transaction storage of the altered value
+ * @author Derek Hulley
+ */
+ private static class TransactionStorage
+ {
+ public Object newValue;
+ }
+}
diff --git a/source/java/org/alfresco/repo/transaction/TransactionAwareSingletonTest.java b/source/java/org/alfresco/repo/transaction/TransactionAwareSingletonTest.java
new file mode 100644
index 0000000000..546c9bcefa
--- /dev/null
+++ b/source/java/org/alfresco/repo/transaction/TransactionAwareSingletonTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2006 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the
+ * License.
+ */
+package org.alfresco.repo.transaction;
+
+import java.util.Random;
+
+import javax.transaction.UserTransaction;
+
+import junit.framework.TestCase;
+
+import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
+import org.alfresco.service.transaction.TransactionService;
+import org.alfresco.util.ApplicationContextHelper;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * @see org.alfresco.repo.transaction.TransactionAwareSingleton
+ *
+ * @author Derek Hulley
+ */
+public class TransactionAwareSingletonTest extends TestCase
+{
+ private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
+ private static Random rand = new Random();
+
+ /** the instance to test */
+ private TransactionAwareSingleton singleton = new TransactionAwareSingleton();
+ private static final Integer INTEGER_ONE = new Integer(1);
+ private static final Integer INTEGER_TWO = new Integer(2);
+
+ private TransactionService transactionService;
+
+ public void setUp() throws Exception
+ {
+ transactionService = (TransactionService) ctx.getBean("transactionComponent");
+ }
+
+ public void testCommit() throws Throwable
+ {
+ UserTransaction txn = transactionService.getUserTransaction();
+ try
+ {
+ txn.begin();
+
+ singleton.put(INTEGER_ONE);
+ check(INTEGER_ONE, true);
+ check(null, false);
+
+ // commit
+ txn.commit();
+ }
+ catch (Throwable e)
+ {
+ try { txn.rollback(); } catch (Throwable ee) {}
+ throw e;
+ }
+ check(INTEGER_ONE, true);
+ check(INTEGER_ONE, false);
+ }
+
+ public void testRollback() throws Throwable
+ {
+ UserTransaction txn = transactionService.getUserTransaction();
+ try
+ {
+ txn.begin();
+
+ singleton.put(INTEGER_TWO);
+ check(INTEGER_TWO, true);
+ check(null, false);
+
+ // rollback
+ txn.rollback();
+ }
+ catch (Throwable e)
+ {
+ try { txn.rollback(); } catch (Throwable ee) {}
+ throw e;
+ }
+ check(null, true);
+ check(null, false);
+ }
+
+ private static final int THREAD_COUNT = 20;
+ public void testThreadsCommit() throws Throwable
+ {
+ TestThread[] threads = new TestThread[THREAD_COUNT];
+ for (int i = 0; i < THREAD_COUNT; i++)
+ {
+ TestThread thread = new TestThread(true);
+ thread.start();
+ threads[i] = thread;
+ }
+ // wait for them to complete
+ for (int i = 0; i < THREAD_COUNT; i++)
+ {
+ while (threads[i].finished == false)
+ {
+ synchronized(this)
+ {
+ try { wait(20); } catch (Throwable e) {}
+ }
+ }
+ if (threads[i].error != null)
+ {
+ throw threads[i].error;
+ }
+ }
+ }
+ public void testThreadsRollback() throws Throwable
+ {
+ TestThread[] threads = new TestThread[THREAD_COUNT];
+ for (int i = 0; i < THREAD_COUNT; i++)
+ {
+ TestThread thread = new TestThread(false);
+ thread.start();
+ threads[i] = thread;
+ }
+ }
+
+ /**
+ * Dumps random values into
+ * @author Derek Hulley
+ */
+ private class TestThread extends Thread
+ {
+ private boolean finished = false;
+ private Throwable error;
+ private boolean commit;
+ private Integer value = new Integer((int)System.nanoTime());
+
+ public TestThread(boolean commit)
+ {
+ this.commit = commit;
+ }
+ @Override
+ public synchronized void run()
+ {
+ UserTransaction txn = transactionService.getUserTransaction();
+ try
+ {
+ txn.begin();
+
+ singleton.put(value);
+
+ // wait for some random time
+ try
+ {
+ wait((long)(rand.nextDouble() * 1000.0)); // wait up to a second
+ }
+ catch (InterruptedException e)
+ {
+ // ignore
+ }
+
+ // check
+ check(value, true);
+
+ if (commit)
+ {
+ txn.commit();
+ }
+ else
+ {
+ // rollback
+ txn.rollback();
+ }
+ }
+ catch (Throwable e)
+ {
+ try { txn.rollback(); } catch (Throwable ee) {}
+ this.error = e;
+ }
+ if (!commit)
+ {
+ try
+ {
+ // no thread changes
+ check(null, false);
+ }
+ catch (Throwable e)
+ {
+ error = e;
+ }
+ }
+ finished = true;
+ }
+ }
+
+ private void check(final Integer expected, boolean inTransaction)
+ {
+ TransactionWork