Moving to root below branch label

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2005 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2005-12-08 07:13:07 +00:00
commit d051d1153c
920 changed files with 98871 additions and 0 deletions

10
.classpath Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="source/java"/>
<classpathentry kind="src" path="config"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="src" path="/Repository"/>
<classpathentry kind="src" path="/Core"/>
<classpathentry combineaccessrules="false" kind="src" path="/Remote API"/>
<classpathentry kind="output" path="build/classes"/>
</classpath>

20
.project Normal file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Web-Client</name>
<comment></comment>
<projects>
<project>3rd Party</project>
<project>Repository</project>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,906 @@
# I18N message properties
# Date Pattern
date_pattern=MMMM, d yyyy
date_time_pattern=MMMM, d yyyy HH:mm
time_pattern=HH:mm
# General UI
product_name=Alfresco
view_description=This view allows you to browse the items in your space.
search_description=This view allows you to see the results from your search.
checkinfile_description=Check in your working copy for other team members to work with.
checkoutfilelink_description=Edit the checked out file, undo the check out or carry on working.
checkoutfile_description=Enter information about the check out.
documentdetails_description=View the details about the content.
previewdocument_description=Preview the content or space within a Template.
spacedetails_description=View the details about the space.
undocheckoutfile_description=Cancel the check out of a document and discard any changes.
updatefile_description=Update a document on the repository with content from your computer.
editfile_description=Edit the content of the file.
editfileinline_description=Edit the content of the document, then click Save.
createfile_description=Enter new content.
manageusers_description=Manage the users of the repository.
manage_invited_users_description=Manage the permissions you have granted to users who access your space.
modify_user_roles_description=Modify the permissions granted to a user for accessing your space.
advancedsearch_description=Perform a more detailed search of the repository.
editdocument_description=Modify the document properties then click OK.
editcategory_description=Set the category for the document then click OK.
editworkflow_description=Modify the simple workflow properties then click OK.
editspace_description=Modify the space properties then click OK.
newspace_description=Enter information about the new space then click Create Space.
space_rules_description=This view shows you all the rules to be applied to content in this space.
warning_inline=This is only recommended for HTML or plain text documents.
categories_description=This view allows you to browse and modify the categories hiearchy.
new_category_description=Enter information about the new Category then click Create Category.
status_message_default=No messages.
# UI Component messages
yes=Yes
no=No
kilobyte=KB
megabyte=MB
gigabyte=GB
locked_you=Item locked by you
locked_user=Item locked by user
wizard_errors=Please correct the errors below.
last_page=Last Page
next_page=Next Page
prev_page=Previous Page
first_page=First Page
page_info=Page {0} of {1}
go_up=Go Up
ok=OK
go=Go
to=To
from=From
options=Options
other_options=Other Options
local=Local
inherited=Inherited
search=Search
advanced_search=Advanced Search
value_not_set=not set
clear=Clear Results
results_contains=Results for ''{0}''.
results_contains_filter=Results for ''{0}'' in ''{1}''.
details_view=Details View
view_icon=Icon View
view_browse=Browse View
more_options=More...
more_actions=More Actions
more_options_space=More Actions for this Space
more_options_file=More Actions for this Document
select_space_prompt=Click here to select a Space
select_existing_space_prompt=Click here to select an existing Space
select_home_space_prompt=Click here to select the Home Space location
select_category_prompt=Click here to select a Category
select_destination_prompt=Click here to select the destination
add_new=Add New
change=Change
set=Set
no_categories_applied=This document does not yet have any categories applied.
has_following_categories=This document has the following categories applied...
moved=moved
copied=copied
document_action=The document will be {0} to ''{1}'' if the ''{2}'' action is taken.
clipboard=Clipboard
recent_spaces=Recent Spaces
shortcuts=Shortcuts
company_home=Company Home
my_home=My Home
advanced_search=Advanced Search
new_search=New Search
search_results=Search Results
search_detail=Search for \"{0}\" results shown below
close_search=Close Search
browse_spaces=Browse Spaces
browse_content=Content items
items=item(s)
location=Item Location
toggle_shelf=Hide or Show the Shelf
shelf=Shelf
actions=Actions
view=View
view_details=View Details
view_details_file=View Details for file
change_details=Change Details
view_details=View Details
update=Update
cut=Cut
copy=Copy
paste=Paste
remove=Remove
change_roles=Change Roles
change_user_roles=Change User Roles
paste_item=Paste Item
paste_all=Paste All
remove_item=Remove Item
remove_all=Remove All
close=Close
invite=Invite
invite_user=Invite User
filter_contents=Filter Contents
users=Users
groups=Groups
resetall=Reset All
content_rules=Content Rules
view_in_browser=View In Browser
view_in_webdav=View in WebDAV
view_in_cifs=View in CIFS
download_content=Download Content
details_page_bookmark=External Access URL
links=Links
create_shortcut=Create Shortcut
navigation=Navigation
next_item=Next Item
previous_item=Previous Item
cancel=Cancel
upload=Upload
homespace=Home Space
network_folder=Open Network Folder
other_action=Run Action
information=Information
move=Move
copy=Copy
type=Type
aspect=Aspect
workflow=Workflow
rules=Rules
system_error=System Error
login=Login
templates=Templates
template=Template
local=Local
select_button=Select...
select_items=Select items
select_an_item=Select an item
selected_items=Selected Items
add_to_list_button=Add to List
none=None
no_selected_items=No selected items.
search_select_item=Search for and select an item.
search_select_items=Search for and select items.
search_minimum=Please enter a minimum of {0} characters to perform a search.
filter=Filter
choose_icon=Choose icon
security=Security
all_formats=All Formats
# Properties
username=User Name
joindate=Join Date
roles=Roles
help=Help
name=Name
password=Password
confirm=Confirm
path=Path
description=Description
created=Created
modified=Modified
created_date=Created Date
modified_date=Modified Date
size=Size
title=Title
author=Author
date=Date
mimetype=Format
# Repo permission display labels
# Note - these come from the server, the english translation is generally the same
Administrator=Administrator
Guest=Guest
Coordinator=Coordinator
Contributor=Contributor
Editor=Editor
All=All
# Actions
delete=Delete
edit=Edit
checkin=Check In
checkout=Check Out
checkout_document=Check out this document
undocheckout=Undo Check Out
delete_space=Delete Space
delete_file=Delete File
delete_rule=Delete Rule
delete_user=Delete User
remove_user=Remove User
new_space=Create Space
add_content=Add Content
create_content=Create Content
add_multiple_files=Add Multiple Files
import_directory=Import Directory
advanced_space_wizard=Advanced Space Wizard
create_rule=Create Rule
manage_rules=Manage Content Rules
manage_users=Manage System Users
manage_groups=Manage User Groups
manage_invited_users=Manage Space Users
modify_user_roles=Modify User Roles for
modify=Modify
view=View
logout=Logout
add=Add
system_info=System Information
node_browser=Node Browser
reset_config=Reset Config Service
save=Save
user_details=User Details
language=Language
export=Export
import=Import
take_ownership=Take Ownership
create_forums=Create Forum Space
create_forum=Create Forum
create_topic=Create Topic
create_post=Create Post
create_reply=Post Reply
delete_forums=Delete Forum Space
delete_forum=Delete Forum
delete_topic=Delete Topic
delete_post=Delete Post
post_to_topic=Post to Topic
reply=Reply
edit_post=Edit Post
reply_to=Reply to
post_reply=Post Reply
# Login page message
login_details=Enter Login details
login_err_password_length=Password must be between {0} and {1} characters in length.
login_err_password_chars=Password can only contain characters or digits.
login_err_username_length=Username must be between {0} and {1} characters in length.
login_err_username_chars=Username can only contain characters or digits.
loggedout_details=You have been logged out of Alfresco.
relogin=Re-login to Alfresco
# Browse list messages
no_space_items=No items to display. Click the ''{0}'' action to create a space.
no_content_items=No items to display. To add an existing document click ''{0}'' action. To create an HTML or Plain Text file click ''{1}'' action.
# Advanced Search messages
look_in=Look in location
look_for=Look for
all_spaces=All Spaces
specify_space=Specify Space
include_child_spaces=Include child spaces
show_results_for=Show me results for
all_items=All Items
file_names_contents=File names and contents
file_names=File names only
space_names=Space names only
show_results_categories=Show me results in the categories
include_sub_categories=Include sub-categories
also_search_results=More search options
additional_options=Additional options
# Forum messages
forums=Forum Space
forum=Forum
browse_forums=Browse Forum Spaces and Forums
browse_topics=Browse Topics
browse_posts=Browse Posts
forums_info=This view allows you to browse forum spaces and forums.
forum_info=This view allows you to browse topics in this forum.
topic_info=This view allows you to browse posts in this topic.
no_forums=No forum spaces or forums to display. Click the ''Create Forum Space'' action to create a forum space or ''Create Forum'' action to create a forum.
no_topics=No topics to display. Click the ''Create Topic'' action to create a topic.
no_posts=No posts to display. Click the ''Post to Topic'' action to create a post.
topic=Topic
topics=Topics
post=Post
posted=Posted
create_forums_description=Enter information about the new forum space then click Create Forum Space.
create_forum_description=Enter information about the new forum then click Create Forum.
create_topic_description=Enter information about the new topic then click Create Topic.
create_post_description=Enter the content of the message then click Post.
create_reply_description=Enter message text to reply then click Reply.
forums_props=Forum Space Properties
forum_props=Forum Properties
topic_props=Topic Properties
create_forums_finish=To create the forum space click Create Forum Space.
create_forum_finish=To create the forum click Create Forum.
create_topic_finish=To create the topic click Create Topic.
create_post_finish=To create the post click Post.
create_reply_finish=To create the reply click Reply.
forums_details_description=View details about the forum space.
forum_details_description=View details about the forum.
topic_details_description=View details about the topic.
bubble_view=Bubble View
replies=Replies
on=On
reply_message=Reply Message
# Common Wizard messages
steps=Steps
summary=Summary
summary_desc=The information you entered is shown below.
default_instruction=To continue click Next.
next_button=Next
back_button=Back
finish_button=Finish
cancel_button=Cancel
clear_button=Clear
title=Title
description=Description
you_may_want=You may want to
# Category Management messages
title_categories_list=Categories
add_category=Add Category
edit_category=Edit Category
delete_category=Delete Category
category_icons=Categories
category_details=Details
category_management=Category Management
title_create_category=Create New Category
new_category=New Category
category_props=Category Properties
items=Items
title_delete_category=Delete Category
delete_category=Delete Category
delete_category_warning=This category has {0} existing document(s) linked to it.
delete_category_info=To remove this category and all it's sub-categories, click Delete.
delete_category_confirm=Are you sure you want to delete category \"{0}\" and all sub-categories?
title_edit_category=Edit Category
edit_category_description=Edit the information for this category.
# Groups Management messages
title_groups_list=Groups Management
groups_management=Groups Management
groups_description=Manage the members of a group, create new groups or remove existing groups.
new_group=Create Group
new_sub_group=Create Sub-Group
edit_group=Edit Group
delete_group=Delete Group
add_user=Add User
group_icons=Groups
group_details=Details
root_groups=Root Groups
group_filter_children=Children
group_filter_all=All
title_create_group=Create Group
new_group_description=Enter information about the new Group then click Create Group.
group_props=Group Properties
identifier=Identifier
create_group_warning=The Identifier for a Group cannot be changed once it has been set.
title_delete_group=Delete Group
delete_group_warning=This group has {0} sub-group(s) or user(s) attached to it.
delete_group_info=To delete this Group from the system and remove all members from it, click Delete.
delete_group_confirm=Once the group is removed from the system it will no longer be accessable. Are you sure you want to delete Group \"{0}\" and remove all users from it?
title_add_user_group=Add User to Group
add_user_group_description=Add an existing User to a Group
select_users=Select Users to add to this Group
selected_users=Selected Users
# Invite Users Wizard messages
invite_title=Invite Users Wizard
invite_desc=This wizard helps you to give other users access to your space.
invite_step1_title=Step One - Invite Users
invite_step1_desc=Select the users and roles they will play in this space.
invite_step2_title=Step Two - Notify Users
invite_step2_desc=Notify the selected users.
i_want_to=I want to...
invite_step_1=Invite Users
invite_step_2=Notify Users
invite_all=Invite All users as guests
invite_users=Specify Users/Groups and their roles
specify_usersgroups=Specify Users/Groups
select_usersgroups=Select user/group and their role(s)
select_role=Select role
selected_usersgroups=Selected users/groups and their role(s)
selected_roles=Selected roles
click_add=Click Add
role=Role
send_email=Do you want to send an email to notify the invited users?
subject=Subject
body=Body
automatic_text=Automatic text
invite_space=You have been invited to ''{0}'' by {1}.
invite_role=You will have the role of: {0}
invite_finish_instruction=To close this wizard and apply your changes click Finish. To review or change your selections click Back.
remove_invited_user_info=Remove an invited user from this space.
add_role=Add Role
space_owner=User ''{0}'' is the current owner of this space.
users_and_groups=Users and Groups
authority=Username
# System Users messages
create_user=Create User
change_password=Change Password
title_change_password=Change User Password
change_password_description=Use this view to change an existing user password.
change_password_instructions=Enter the new password for this user.
# Check-in messages
check_in=Check In
checkin_options=Check In options
checkin_changes_info=Check in changes and keep file checked out
workingcopy_location=Working copy location
which_copy_checkin=Which copy do you want to check in?
which_copy_current=Use copy in current space
which_copy_other=Use copy uploaded from my computer
locate_doc_upload=Locate document to upload
file_location=Location
click_upload=Click upload
minor_change=Minor Change
major_change=Major Change
notes=Notes
# Check-out messages
check_out=Check Out
copy_work_with=A copy of the file ''{0}'' will be made for you to work with.
copy_checkin_changes=When you have completed your changes you need to check in the file to allow others to view the changes.
copy_store_prompt=Where do you want to keep the copy of this file?
store_space_current=In the current space
store_space_selected=In the space selected
check_out_of=Check Out of
copy_file_checkedout=A copy of the file ''{0}'' is now checked out to you for editing.
edit_workingcopy_title=Edit the working copy now
edit_workingcopy_info=To edit the working copy of the file, click the link below and if asked select Save.
continue_working_title=Continue working
continue_working_info1=If you do not want to edit the file now click OK to close the page.
continue_working_info2=To edit the file in the future click the Edit action
download_complete=When the download is complete, click OK.
undo_checkout_for=Undo Check Out for
undo_checkout=Undo Check Out
undo_checkout_info=If you undo the check out of a document, the associated working copy will be deleted and all changes to it since the Check Out will be lost.
# Document and Space details messages
details_of=Details of
preview_of=Preview of
modify_props_of=Modify Properties of
preview=Preview in Template
dashboard_view=Dashboard View
dashboard=Dashboard
view_links=Links
not_inline_editable=This document is not inline editable.
allow_inline_editing=Allow Inline Editing
not_in_workflow=This document is not part of any workflow.
not_in_category=This document is not categorized.
not_versioned=This document has no version history.
allow_categorization=Allow Categorization
allow_versioning=Allow Versioning
version_history=Version History
version=Version
document_properties=Document Properties
other_properties=Other Properties
no_other_properties=This document does not have any other properties to show.
modify_categories_of=Modify categories of
space_props=Space Properties
choose_space_icon=Choose space icon
create_space_finish=To create your space click Create Space.
select_category=Select a category
selected_categories=Selected categories
no_selected_categories=No categories selected.
success_ownership=Successfully took ownership of the document.
inherit_permissions=Inherit Parent Space Permissions
success_inherit_permissions=Successfully changed Inherit Parent Permissions to 'Yes'
success_not_inherit_permissions=Successfully changed Inherit Parent Permissions to 'No'
apply_dashboard=Apply Dashboard
apply_dashboard_info=Select a template to be applied to the Space as a Dashboard view.
# Export messages
export_info=Exports metadata and content from this or all Spaces.
export_from=Export From
package_name=Package Name
all_spaces=Repository Root
current_space=Current Space
include_children=Include Children
include_self=Include this Space
run_export_in_background=Run export in background
export_error_info=If this option is selected the export will be performed in the background so the results may not appear immediately. You may also want to monitor the server console and log files for errors.
# Import messages
import_info=Imports an Alfresco content package file into the repository.
import_package_description=Alfresco content package
run_import_in_background=Run import in background
import_error_info=If this option is selected the import will be performed in the background so the results may not appear immediately. You may also want to monitor the server console and log files for errors.
# Edit Content messages
edit_file_title=Edit file
edit_file_prompt=To edit the file ''{0}'', click the link below and if asked select Save.
edit_download_complete=When the download is complete, click Close.
checkout_file_title=Check out file
checkout_you_may_want=You may want to check out this file to lock it and prevent other users from editing it.
checkout_hint1=Hint: When you check out a file a copy is made for you to work with.
checkout_hint2=When you have finished editing the copy you need to check it in to release the lock and allow others to work with the modified document.
checkout_want_to=to prevent the possibility of other users overwriting your changes.
checkout_warn=Note: You will lose any changes already made to this document.
local_copy_location=Local copy location
locate_content_upload=Locate and upload your document to the repository.
# Edit Workflow messages
modify_workflow_props=Modify Properties of Simple Workflow
approve_flow=Approve Flow
reject_flow=Reject Flow
name_approve_step=Name for approve step
name_reject_step=Name for reject step
select_reject_step=Do you want to provide a reject step?
choose_copy_move_location=Choose whether you want to move or copy the content and also the location.
# System Information and admin page messages
system_info=System Information
current_user=Current User
http_app_state=HTTP Application State
http_session_state=HTTP Session State
http_request_state=HTTP Request State
http_request_params=HTTP Request Parameters
http_request_headers=HTTP Request Headers
system_props=System Properties
hide_details=Hide Details
show_details=Show Details
# Content Wizard messages
add_content_title=Add Content Wizard
add_content_desc=This wizard helps you to add a document to a space.
add_conent_step1_title=Step One - Upload Document
add_conent_step1_desc=Locate and upload your document to the repository.
add_conent_step2_title=Step Two - Properties
add_conent_step2_desc=Enter information about this content.
upload_document=Upload Document
properties=Properties
general=General
file_name=File Name
content_type=Content Type
content_format=Content Format
author=Author
inline_editable=Inline Editable
locate_document=Locate document to upload
location=Location
click_upload=Click upload
file_upload_success=The file ''{0}'' was uploaded successfully. If the file you uploaded does not exist, then an empty file will be created with the name you specified.
content_finish_instruction=To add the content to this space click Finish. To review or change your selections click Back.
create_content_title=Create Content Wizard
create_content_desc=This wizard helps you to create a new document in a space.
create_content_step1_title=Step One - Select Type
create_content_step1_desc=Select the type of content you wish to create.
create_content_step2_title=Step Two - Enter Content
create_content_step2_desc=Enter your document content into the repository.
create_content_step3_title=Step Three - Properties
create_content_step3_desc=Enter information about this content.
enter_content=Enter Content
select_type=Select Type
content=Content
text_content=Plain Text Content
html_content=HTML Content
# Rule and Action Wizard messages
create_action_title=Custom Action Wizard
create_action_desc=This wizard helps you create a custom action for
create_action_step1_title=Step One - Select Action
create_action_step2_title=Step Two - Action Settings
create_action_finish_instruction=To execute the action click Finish. To review or change your selections click Back.
new_rule_title=New Rule Wizard
new_rule_title_edit=Edit Rule Wizard
new_rule_desc=This wizard helps you create a new rule.
new_rule_desc_edit=This wizard helps you modify a rule.
new_rule_step1_title=Step One - Enter Details
new_rule_step2_title=Step Two - Select Conditions
new_rule_step3_title=Step Three - Select Actions
new_rule_finish_instruction=To create the rule click Finish. To review or change your selections click Back.
new_rule_finish_instruction_edit=To update the rule click Finish. To review or change your selections click Back.
select_action=Select Action
select_an_action=Select an action...
action=Action
actions=Actions
action_settings=Action Settings
set_action_values=Set action values
select_feature=Select required feature
version_notes=Version Notes
checkout_location=Check out location
destination=Destination
subject=Subject
message=Message
category=Category
categories=Categories
change_category=Change Category
approve_flow=Approve Flow
approve_step_name=Name for approve step
move_or_copy=Choose whether you want to move or copy the content and also the location.
reject_flow=Reject Flow
want_reject_step=Do you want to provide a reject step?
reject_step_name=Name for reject step
required_format=Required format
details=Details
select_condition=Select Condition
select_a_condition=Select a condition...
condition=Condition
conditions=Conditions
condition_settings=Condition Settings
set_condition_values=Set condition values
select_checkout_prompt=Click here to select the check out location
condition_contains_desc=Enter the text pattern required, including any wildcards. The file name includes the file type extension when matching.
file_name_pattern=File name pattern
condition_contains_hints=Hints
condition_contains_hints_desc=Use zz* to match any name that begins with zz; use *.txt to match any text file; use *zz* to match any file name that contains zz anywhere including the beginning or end.
apply_to_sub_spaces=Apply rule to sub spaces
run_in_background=Run rule in background
not=Not
click_set_and_add=Click to set values and add to list
click_add=Click to add to list
set_and_add_button=Set Values and Add
selected_conditions=Selected Rule Conditions
selected_actions=Selected Rule Actions
condition_no_condition=Match any item
condition_has_aspect=Item has aspect
condition_has_aspect_not=Item does not have aspect
condition_is_subtype=Item is a subtype of
condition_is_subtype_not=Item is not a subtype of
condition_compare_mime_type=Item has a mimetype of
condition_compare_mime_type_not=Item does not have a mimetype of
condition_in_category=Item is in category
condition_in_category_not=Item is not in category
condition_compare_property_value=Name property matches
condition_compare_property_value_not=Name property does not match
action_add_features=Add aspect
action_specialise_type=Item is specialised to type
action_simple_workflow={0} item to ''{1}'' if ''{2}'' action is taken.
action_link_category=Link to category
action_transform=Copies content to ''{0}'' and transforms to ''{1}''
action_transform_image=Copies image to ''{0}'' and transforms to ''{1}'' using option ''{2}''
action_copy=Copy to
action_extract_metadata=Extract metadata from content
action_move=Move to
action_mail=Send email to
action_check_in=Check in content as ''{0}'' with comment ''{1}''
action_check_out=Check out content to
action_set_property_value=Sets property
action_import=Imports to
not_condition_result=Check the item does not match the criteria above
space=Space
import_to=Import To
encoding=Encoding
encoding_utf8=UTF-8
rule_type=Rule Type
rule_background_info=If this option is selected the rule will execute in the background so the results may not appear immediately.
# New Space Wizard messages
new_space_title=New Space Wizard
new_space_desc=This wizard helps you to create a new space.
new_space_step1_title=Step One - Starting Space
new_space_step1_desc=Choose how you want to create your space.
new_space_step2_title=Step Two - Space Options
new_space_step2_desc=Select space options.
new_space_step3_title=Step Three - Space Details
new_space_step3_desc=Enter information about the space.
new_space_finish_instruction=To close this wizard and create your space click Finish. To review or change your selections click Back.
scratch=Scratch
an_existing_space=An existing space
a_template=A template
creating_from=Creating From
save_as_template=Save As Template
template_name=Template Name
select_a_template=Select a template...
starting_space=Starting Space
space_options=Space Options
space_details=Space Details
how_to_create_space=How do you want to create your space?
from_scratch=From scratch
based_on_existing_space=Based on an existing space
using_a_template=Using a template
choose_space_icon=Choose space icon
existing_space=Existing Space
copy_existing_space=Copy existing space
structure=Structure
structure_contents=Structure and contents
space_copy_note=Note: Any content rules for spaces will also be copied.
space_type=Space Type
space_type_create=Select the type of space you want to create.
container=Folder Space
container_desc=A place for keeping and organizing documents and other spaces.
forums_desc=A place to discuss content with other users.
space_type_note=Note: If you can only see one type of space then other space types may not be enabled. See your System Administrator for further help.
template_space=Template Space
select_template=Select the template you want to use.
# New User Wizard messages
new_user_title=New User Wizard
new_user_title_edit=Edit User Wizard
new_user_desc=This wizard helps you to add a user to the repository.
new_user_desc_edit=This wizard helps you modify a user in the repository.
new_user_step1_title=Step One - Person Properties
new_user_step1_desc=Enter information about this person.
new_user_step2_title=Step Two - User Properties
new_user_step2_desc=Enter information about this user.
new_user_finish_instruction=To add the user to this space click Finish. To review or change your selections click Back.
person_properties=Person Properties
user_properties=User Properties
first_name=First Name
last_name=Last Name
email=Email
company_id=Company ID
home_space_location=Home Space Location
home_space_name=Home Space Name
# Admin Console messages
title_admin_console=Administration Console
admin_console=Administration Console
admin_description=Use this view to perform system administration functions.
# UI Page Titles
title_about=About Alfresco
title_login=Alfresco Web Client - Login
title_relogin=Alfresco Web Client - Logged Out
title_error=Alfresco Web Client - System Error
title_browse=Alfresco Web Client
title_create_space=Create Space
title_inviteusers_invite=Invite Users - Invite
title_inviteusers_notify=Invite Users - Notify
title_change_user_roles=Change User Roles
title_remove_invited_user=Remove Invited User
title_advanced_search=Advanced Search
title_checkin_file=Check In File
title_checkout_file=Check Out File
title_checkout_file_link=Check Out File Download
title_delete_file=Delete File
title_delete_rule=Delete Rule
title_delete_user=Delete User
title_delete_space=Delete Space
title_file_details=Document Details
title_file_preview=Preview In Template
title_edit_categories=Edit Categories
title_edit_doc_props=Edit Document Properties
title_edit_file=Edit File
title_edit_html_inline=Edit HTML File Inline
title_edit_text_inline=Edit Text File Inline
title_edit_simple_workflow=Edit Simple Workflow
title_edit_space=Edit Space Details
title_rules=Space Rules
title_space_details=Space Details
title_system_info=System Information
title_undo_checkout=Undo Check Out
title_update_file=Update File Content
title_users=User Management
title_invited_users=Manage Invited Users
title_add_content_props=Add Content - Properties
title_add_content_summary=Add Content - Summary
title_add_content_upload=Add Content - Upload
title_create_content=Create New Content
title_create_content_props=Create New Content - Properties
title_create_content_summary=Create New Content - Summary
title_create_action_action=Create Action - Select Action
title_create_action_add_feature=Create Action - Add Feature
title_create_action_checkin=Create Action - Check In
title_create_action_checkout=Create Action - Check Out
title_create_action_copy=Create Action - Copy
title_create_action_import=Create Action - Import
title_create_action_email=Create Action - Email
title_create_action_link_category=Create Action - Link Category
title_create_action_move=Create Action - Move
title_create_action_simple_workflow=Create Action - Simple Workflow
title_create_action_transform=Create Action - Transform
title_create_action_transform_image=Create Action - Transform Image
title_create_specialise_action=Create Action - Specialise Type
title_create_action_summary=Create Action - Summary
title_new_rule_action=New Rule - Select Action
title_new_rule_add_feature=New Rule - Add Feature
title_specialise_type_action=New Rule - Specialise Type
title_new_rule_checkin=New Rule - Check In
title_new_rule_checkout=New Rule - Check Out
title_new_rule_copy=New Rule - Copy
title_new_rule_email=New Rule - Email
title_new_rule_link_category=New Rule - Link Category
title_new_rule_move=New Rule - Move
title_new_rule_simple_workflow=New Rule - Simple Workflow
title_new_rule_transform=New Rule - Transform
title_new_rule_transform_image=New Rule - Transform Image
title_new_rule_import=New Rule - Import
title_new_rule_condition=New Rule - Conditions
title_new_rule_cond_contains=New Rule - Contains Text
title_new_rule_cond_mimetype=New Rule - Has Mimetype
title_new_rule_cond_category=New Rule - In Category
title_new_rule_cond_subtype=New Rule - Is Subtype
title_new_rule_cond_aspect=New Rule - Has Subtype
title_new_rule_details=New Rule - Details
title_new_rule_summary=New Rule - Summary
title_new_space_create-from=New Space - Create From
title_new_space_details=New Space - Details
title_new_space_existing=New Space - From Existing
title_new_space_scratch=New Space - From Scratch
title_new_space_template=New Space - From Template
title_new_space_summary=New Space - Summary
title_new_user_person_props=User - Person Properties
title_new_user_user_props=User - User Properties
title_new_user_summary=User - Summary
title_export=Export
title_import=Import
title_admin_store_browser=Alfresco Store Browser
title_admin_node_browser=Alfresco Node Browser
title_admin_search_results=Node Browser Search Results
title_forums=Forum Space
title_forum=Forum
title_topic=Topic
title_delete_forums_space=Delete Forum Space
title_delete_forum_space=Delete Forum
title_delete_topic_space=Delete Topic
title_delete_post=Delete Post
title_create_forums=Create Forum Space
title_create_forum=Create Forum
title_forums_details=Forum Space Details
title_forum_details=Forum Details
title_create_topic=Create Topic
title_topic_details=Topic Details
title_create_post=Post Message
title_create_reply=Create Reply
# UI Error messages
error_generic=A system error happened during the operation: {0}
error_noderef=Unable to find the repository item referenced by Id: {0} - the record has probably been deleted from the database.
error_deleted_folder=The folder item referenced by Id: {0} - has been deleted from the database. The system has changed your folder location as the folder you were in no longer exists.
error_homespace=The Home Space node referenced by Id: {0} cannot be found. It may have been deleted from the database. Please contact your system administrator.
error_search=Search failed due to system error: {0}
error_exists=A Space or File with that name already exists: {0}
error_delete_space=Unable to delete Space due to system error:
error_delete_file=Unable to delete File due to system error:
error_checkout=Unable to check out Content Node due to system error:
error_update=Unable to update Content Node due to system error:
error_cancel_checkout=Unable to cancel check out of Content Node due to system error:
error_checkin=Unable to check in Content Node due to system error:
error_paste=Unable to paste item due to system error:
error_login_user=Unable to login - unknown username/password.
error_login_missing=Must specify username and password.
error_delete_rule=Unable to delete Rule due to system error:
error_action=Failed to run Action due to error: {0}
error_rule=Failed to create Rule due to error: {0}
error_space=Failed to create new space due to error: {0}
error_person=Failed to create Person due to error: {0}
error_delete_user=Failed to delete User due to error: {0}
error_remove_user=Failed to remove User due to error: {0}
error_password_match=Please ensure that both password fields contain the same value.
error_property=Property ''{0}'' is not available for this node
error_child_association=Child association ''{0}'' is not available for this node
error_not_child_association=The association named ''{0}'' is not a child association
error_association=Association ''{0}'' is not available for this node
error_not_association=The association named ''{0}'' is not an association
error_create_space_dialog=Please correct the errors below then click Create Space.
error_create_forums_dialog=Please correct the errors below then click Create Forum Space.
error_create_forum_dialog=Please correct the errors below then click Create Forum.
error_create_topic_dialog=Please correct the errors below then click Create Topic.
error_create_post_dialog=Please correct the errors below then click Post.
error_create_reply_dialog=Please correct the errors below then click Reply.
error_create_category_dialog=Please correct the errors below then click New Category.
error_create_group_dialog=Please correct the errors below then click Create Group.
error_wizard=Please correct the errors below then click Finish.
error_update_category=Failed to update category due to system error: {0}
error_update_simpleworkflow=Failed to update simple workflow due to system error: {0}
error_workflow_approve=Failed to approve the document due to system error: {0}
error_workflow_reject=Failed to reject the document due to system error: {0}
error_aspect_classify=Failed to apply the ''classifiable'' aspect to the document due to system error: {0}
error_aspect_versioning=Failed to apply the ''versionable'' aspect to the document due to system error: {0}
error_aspect_inlineeditable=Failed to apply the ''inlineeditable'' aspect to the document due to system error: {0}
error_content_missing=The node''s content is missing: \n node: {0} \n reader: {1} \nPlease contact your system administrator.
error_export=Failed to execute export: {0}
error_import=Failed to execute import: {0}
error_import_no_file=Can not find an ACP file to import!
error_import_empty_file=You can not import an empty ACP file!
error_import_all=Please correct the import errors below then click OK.
error_export_all=Please correct the export errors below then click OK.
# Confirmations
return_to_application=Return to application
delete_space_info=To remove this space and all of its contents, click Delete.
delete_space_confirm=Are you sure you want to delete \"{0}\" and all its contents?
delete_forums_info=To remove this forum space and its contents, click Delete.
delete_forum_info=To remove this forum and its topics, click Delete.
delete_forum_confirm=Are you sure you want to delete \"{0}\" and all its topics?
delete_topic_info=To remove this topic and its posts, click Delete.
delete_topic_confirm=Are you sure you want to delete \"{0}\" and all its posts?
delete_post_info=To remove this post, click Delete.
delete_post_confirm=Are you sure you want to delete \"{0}\"?
delete_file_info=To remove this file and any previous versions, click Delete.
delete_file_confirm=Are you sure you want to delete \"{0}\" and all previous versions?
delete_rule_info=To remove this rule, click Delete.
delete_user_info=To delete this user, click Delete.
delete_rule_confirm=Are you sure you want to delete \"{0}\"?
delete_user_confirm=Are you sure you want to delete user \"{0}\"? The User will no longer be able to access the system.
remove_invited_user_confirm=Are you sure you want to remove user \"{0}\"? The User will no longer be able to access the documents and folders in this space.
delete_companyroot_confirm=WARNING: This folder is a special folder accessed by all Users! Please be sure that you wish to delete this folder. It may cause System Errors if you remove it.
# Status Messages
status_space_created=Successfully created space ''{0}''.
status_space_deleted=Successfully deleted space ''{0}''.
status_space_updated=Successfully updated space ''{0}''.

View File

@@ -0,0 +1,20 @@
<#-- Table of the images found in a folder under Company Home called "Company Logos" -->
<#-- Shows each image found as inline content -->
<table>
<#list companyhome.children as child>
<#if child.isContainer && child.name = "Company Logos">
<#list child.children as image>
<#switch image.mimetype>
<#case "image/jpeg">
<#case "image/gif">
<#case "image/png">
<tr>
<td><img src="/alfresco${image.url}"></td>
</tr>
<#break>
<#default>
</#switch>
</#list>
</#if>
</#list>
</table>

View File

@@ -0,0 +1,17 @@
<#-- Shows some general info about the current document, including NodeRef and aspects applied -->
<h3>=====Template Start=====</h3>
<h4>Current Document Info:</h4>
<b>Name:</b> ${document.name}<br>
<b>Ref:</b> ${document.nodeRef}<br>
<b>Type:</b> ${document.type}<br>
<b>Content URL:</b> <a href="/alfresco${document.url}">/alfresco${document.url}</a><br>
<b>Locked:</b> <#if document.isLocked>Yes<#else>No</#if><br>
<b>Aspects:</b>
<table>
<#list document.aspects as aspect>
<tr><td>${aspect}</td></tr>
</#list>
</table>
<h3>=====Template End=====</h3>

View File

@@ -0,0 +1,47 @@
<h3>=====Example Template Start=====</h3>
<b>Company Home Space:</b> ${companyhome.properties.name}
<br>
<b>My Home Space:</b> ${userhome.properties.name}
<br>
<b>Company Home children count:</b> ${companyhome.children?size}
<br>
<b>Company Home first child node name:</b> ${companyhome.children[0].properties.name}
<br>
<b>Current Document Name:</b> ${document.name}
<br>
<b>Current Space Name:</b> ${space.name}
<h4>List of child spaces in my Home Space:</h4>
<table>
<#list userhome.children as child>
<#if child.isContainer>
<tr>
<td><img src="/alfresco${child.icon32}"></td>
<td><b>${child.properties.name}</b> (${child.children?size})</td>
<td><b>Path:</b> ${child.displayPath}</td>
</tr>
</#if>
</#list>
</table>
<h4>List of docs in my Home Space (text only content shown inline, JPG images shown as thumbnails):</h4>
<table>
<#list userhome.children as child>
<#if child.isDocument>
<tr><td><img src="/alfresco${child.icon16}"></td><td><a href="/alfresco${child.url}">${child.properties.name}</a></td></tr>
<#if child.mimetype = "text/plain">
<tr><td></td><td>${child.content}</td></tr>
<#elseif child.mimetype = "image/jpeg">
<tr><td></td><td><img width=100 height=65 src="/alfresco${child.url}"></td></tr>
</#if>
</#if>
</#list>
</table>
<h4>Assoc example:</h4>
<#if userhome.children[0].assocs["cm:contains"]?exists>
${userhome.children[0].assocs["cm:contains"][0].name}
</#if>
<h3>=====Example Template End=====</h3>

View File

@@ -0,0 +1,10 @@
<#-- Shows if a document is localizable and the locale if set -->
<b>Localisable:</b>
<#if hasAspect(document, "cm:localizable") = 1>
Yes<br>
<#if document.properties.locale?exists>
Locale: ${document.properties.locale.properties.name}
</#if>
<#else>
No<br>
</#if>

View File

@@ -0,0 +1,20 @@
<#-- Table of the documents in my Home Space -->
<#-- Shows the Icon and link to the content for the doc, also the size in KB and lock status -->
<table>
<tr>
<td></td>
<td><b>Name</b></td>
<td><b>Size</b></td>
<td><b>Locked</b></td>
</tr>
<#list userhome.children as child>
<#if child.isDocument>
<tr>
<td><a href="/alfresco${child.url}" target="new"><img src="/alfresco${child.icon16}" border=0></a></td>
<td><a href="/alfresco${child.url}" target="new">${child.properties.name}</a></td>
<td>${(child.size / 1000)?string("0.##")} KB</td>
<td>&nbsp;<#if child.isLocked>Yes</#if></td>
</tr>
</#if>
</#list>
</table>

View File

@@ -0,0 +1,28 @@
<#-- Displays a table of all the documents from a "Press Releases" folder under Company Home -->
<#-- Obviously this folder needs to exist and the docs in it should have the title and description fields set -->
<table>
<#list companyhome.children as child>
<#if child.isContainer && child.name = "Press Releases">
<#list child.children as doc>
<#if doc.isDocument>
<tr>
<td><a class="title" href="/alfresco/${doc.url}">${doc.properties.title}</a></td>
</tr>
<tr>
<td style="padding-left:4px"><b>${doc.properties.description}</b></td>
</tr>
<tr>
<td style="padding-left:8px">
<#if (doc.content?length > 500)>
<small>${doc.content[0..500]}...</small>
<#else>
<small>${doc.content}</small>
</#if>
</td>
</tr>
<tr><td><div style="padding:6px"></div></td></tr>
</#if>
</#list>
</#if>
</#list>
</table>

View File

@@ -0,0 +1,15 @@
<#-- Table of the Spaces in my Home Folder -->
<#-- Shows the large 32x32 pixel icon, and generates an external access servlet URL to the space -->
<table>
<#list userhome.children as child>
<#if child.isContainer>
<tr>
<td><img src="/alfresco${child.icon32}"></td>
<#assign ref=child.nodeRef>
<#assign workspace=ref[0..ref?index_of("://")-1]>
<#assign storenode=ref[ref?index_of("://")+3..]>
<td><a href="/alfresco/navigate/showSpaceDetails/${workspace}/${storenode}"><b>${child.properties.name}</b></a> (${child.children?size})</td>
</tr>
</#if>
</#list>
</table>

View File

@@ -0,0 +1,8 @@
<#-- Table of some summary details about the current user -->
<table>
<tr><td><b>Name:</b></td> <td>${person.properties.firstName} ${person.properties.lastName}</td></tr>
<tr><td><b>User:</b></td> <td>${person.properties.userName}</td></tr>
<tr><td><b>Home Space location:</b></td> <td>${userhome.displayPath}/${userhome.name}</td></tr>
<tr><td><b>Items in Home Space:</b></td> <td>${userhome.children?size}</td></tr>
<tr><td><b>Items in Company Space:</b></td> <td>${companyhome.children?size}</td></tr>
</table>

View File

@@ -0,0 +1,19 @@
<#-- Shows use of the childByNamePath and childrenByXPath API -->
<h3>Template Documents in 'Company Home/Data Dictionary/Content Templates':</h3>
<table>
<#list companyhome.childByNamePath["Data Dictionary/Content Templates"].children as child>
<#if child.isDocument>
<tr><td><a href="/alfresco${child.url}" target="new">${child.properties.name}</a></td></tr>
</#if>
</#list>
</table>
<h3>Folders in 'Company Home/Data Dictionary/Space Templates/Software Engineering Project':</h3>
<table>
<#list companyhome.childrenByXPath["*[@cm:name='Data Dictionary']/*[@cm:name='Space Templates']/*[@cm:name='Software Engineering Project']/*"] as child>
<#if child.isContainer>
<tr><td><img src="/alfresco${child.icon32}"> ${child.properties.name}</td></tr>
</#if>
</#list>
</table>

View File

@@ -0,0 +1,20 @@
<#-- Table of docs in a specific folder, that have been created or modified in the last week -->
<h3>Documents created or modified in the last week</h3>
<table cellpadding=2>
<tr>
<td></td>
<td><b>Name</b></td>
<td><b>Created Date</b></td>
<td><b>Modified Date</b></td>
</tr>
<#list space.childrenByXPath[".//*[subtypeOf('cm:content')]"] as child>
<#if (dateCompare(child.properties["cm:modified"], date, 1000*60*60*24*7) == 1) || (dateCompare(child.properties["cm:created"], date, 1000*60*60*24*7) == 1)>
<tr>
<td><a href="/alfresco${child.url}" target="new"><img src="/alfresco${child.icon16}" border=0></a></td>
<td><a href="/alfresco${child.url}" target="new">${child.properties.name}</a></td>
<td>${child.properties["cm:created"]?datetime}</td>
<td>${child.properties["cm:modified"]?datetime}</td>
</tr>
</#if>
</#list>
</table>

View File

@@ -0,0 +1,17 @@
<h3>System users, company Ids and home space information</h3>
<table cellpadding=2>
<tr>
<td><b>Company ID</b></td>
<td><b>Username</b></td>
<td><b>Home Space Path</b></td>
<td><b>Creation Date</b></td>
</tr>
<#list space.childrenByXPath["/sys:system/sys:people/*[subtypeOf('cm:person')]"] as child>
<tr>
<td>${child.properties["cm:organizationId"]}</td>
<td>${child.properties["cm:userName"]}</td>
<td>${child.properties["cm:homeFolder"].displayPath}</td>
<td>${child.properties["cm:homeFolder"].properties["cm:created"]?date}</td>
</tr>
</#list>
</table>

View File

@@ -0,0 +1,12 @@
<#-- Shows the translations applied to a doc through the translatable aspect -->
<b>Translatable:</b>
<#if hasAspect(document, "cm:translatable") = 1>
Yes<br>
<table>
<#list document.assocs["cm:translations"] as t>
<tr><td>${t.content}</td></tr>
</#list>
</table>
<#else>
No<br>
</#if>

View File

@@ -0,0 +1,15 @@
<#-- List of docs in the Home Space for current user -->
<#-- If the doc mimetype is plain/text then the content is shown inline -->
<#-- If the doc mimetype is JPEG then the image is shown inline as a small thumbnail image -->
<table>
<#list userhome.children as child>
<#if child.isDocument>
<tr><td>${child.properties.name}</td></tr>
<#if child.mimetype = "text/plain">
<tr><td style='padding-left:16px'>${child.content}</td></tr>
<#elseif child.mimetype = "image/jpeg">
<tr><td style='padding-left:16px'><img width=100 height=65 src="/alfresco${child.url}"><td></tr>
</#if>
</#if>
</#list>
</table>

View File

@@ -0,0 +1,28 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<bean id="configSource" class="org.alfresco.config.source.ClassPathConfigSource">
<constructor-arg>
<list>
<value>alfresco/web-client-config.xml</value>
<value>alfresco/web-client-config-edit-properties.xml</value>
</list>
</constructor-arg>
</bean>
<bean id="configService" class="org.alfresco.config.xml.XMLConfigService" init-method="init">
<constructor-arg>
<ref bean="configSource"/>
</constructor-arg>
</bean>
<!-- NOTE: This references a bean in the repository Spring configuration -->
<bean id="dataDictionary" class="org.alfresco.web.bean.repository.DataDictionary">
<constructor-arg>
<ref bean="DictionaryService"/>
</constructor-arg>
</bean>
</beans>

View File

@@ -0,0 +1,86 @@
<alfresco-config area="edit-properties">
<!-- Example Client Configuration for exposing Types in exampleModel.xml -->
<config evaluator="node-type" condition="my:sop">
<property-sheet>
<show-property name="my:publishedDate"/>
<show-association name="my:signOff"/>
<show-property name="my:authorisedBy"/>
<show-child-association name="my:processSteps"/>
</property-sheet>
</config>
<!-- End Example -->
<config evaluator="node-type" condition="dictionaryModel">
<property-sheet>
<show-property name="modelActive"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="complianceable">
<property-sheet>
<show-property name="removeAfter"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="dublincore">
<property-sheet>
<show-property name="publisher"/>
<show-property name="contributor"/>
<show-property name="type"/>
<show-property name="identifier"/>
<show-property name="dcsource"/>
<show-property name="coverage"/>
<show-property name="rights"/>
<show-property name="subject"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="effectivity">
<property-sheet>
<show-property name="from"/>
<show-property name="to"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="summarizable">
<property-sheet>
<show-property name="summary"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="versionable">
<property-sheet>
<show-property name="autoVersion" converter="org.alfresco.faces.BooleanLabelConverter"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="translatable">
<property-sheet>
<show-association name="translations"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="localizable">
<property-sheet>
<show-property name="locale"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="app:inlineeditable">
<property-sheet>
<show-property name="app:editInline"/>
</property-sheet>
</config>
<!-- Example Client Configuration for exposing Aspects in exampleModel.xml -->
<config evaluator="aspect-name" condition="my:imageClassification">
<property-sheet>
<show-property name="my:width"/>
<show-property name="my:height"/>
<show-property name="my:resolution"/>
</property-sheet>
</config>
<!-- End Example -->
</alfresco-config>

View File

@@ -0,0 +1,10 @@
<alfresco-config>
<plug-ins>
<evaluators>
<evaluator id="type-name" class="jsftest.repository.TypeNameEvaluator"/>
<evaluator id="aspect" class="org.alfresco.web.config.AspectEvaluator"/>
</evaluators>
</plug-ins>
</alfresco-config>

View File

@@ -0,0 +1,325 @@
<alfresco-config>
<plug-ins>
<evaluators>
<evaluator id="node-type" class="org.alfresco.web.config.NodeTypeEvaluator" />
<evaluator id="aspect-name" class="org.alfresco.web.config.AspectEvaluator" />
</evaluators>
<element-readers>
<element-reader element-name="server" class="org.alfresco.web.config.ServerElementReader"/>
<element-reader element-name="client" class="org.alfresco.web.config.ClientElementReader"/>
<element-reader element-name="property-sheet" class="org.alfresco.web.config.PropertySheetElementReader"/>
<element-reader element-name="navigation" class="org.alfresco.web.config.NavigationElementReader" />
</element-readers>
</plug-ins>
<config>
<server>
<error-page>/jsp/error.jsp</error-page>
<error-pages>
<error-page>/jsp/error.jsp</error-page>
<error-page type="org.alfresco.service.cmr.repository.InvalidNodeRefException">
/jsp/error_missing.jsp
</error-page>
</error-pages>
<login-page>/jsp/login.jsp</login-page>
</server>
<admin>
<initial-password>admin</initial-password>
</admin>
<client>
<!-- the list of available language files -->
<languages>
<language locale="en_US">English</language>
<!-- <language locale="fr_FR">French</language> -->
<!-- <language locale="de_DE">German</language> -->
<!-- <language locale="ja_JP">Japanese</language> -->
</languages>
<!-- advanced search custom attribute config -->
<advanced-search>
<!-- type constraint drop-down -->
<content-types>
<!-- cm:content type is implicit in this list -->
<!-- types must extend cm:content for the Alfresco web-client -->
<type name="cm:dictionaryModel" />
<type name="fm:post" />
</content-types>
<!-- custom properties to be shown in the More Options panel -->
<custom-properties>
</custom-properties>
</advanced-search>
<!-- the views available in the client -->
<views>
<view>org.alfresco.web.ui.common.renderer.data.RichListRenderer$DetailsViewRenderer</view>
<view>org.alfresco.web.ui.common.renderer.data.RichListRenderer$IconViewRenderer</view>
<view>org.alfresco.web.ui.common.renderer.data.RichListRenderer$ListViewRenderer</view>
<view>org.alfresco.web.bean.ForumsBean$TopicBubbleViewRenderer</view>
</views>
<!-- default values for the views available in the client -->
<view-defaults>
<browse>
<!-- allowable values: list|details|icons -->
<view>icons</view>
<page-size>
<list>10</list>
<details>10</details>
<icons>9</icons>
</page-size>
</browse>
<forums>
<!-- allowable values: list|details|icons -->
<view>list</view>
<page-size>
<list>20</list>
<details>20</details>
<icons>20</icons>
</page-size>
</forums>
<forum>
<!-- allowable values: details -->
<view>details</view>
<page-size>
<details>20</details>
</page-size>
</forum>
<topic>
<!-- allowable values: details|bubble -->
<view>bubble</view>
<sort-column>created</sort-column>
<sort-descending>true</sort-descending>
<page-size>
<bubble>5</bubble>
<details>20</details>
</page-size>
</topic>
</view-defaults>
<!-- the maximum number of items to show in the recent spaces shelf component -->
<recent-spaces-items>6</recent-spaces-items>
<!-- the minimum number of characters required for a valid search string -->
<search-minimum>3</search-minimum>
<!-- The default permissions to apply to a new users Home Space when first created -->
<!-- this permission is for other users attempting to access that Home Space -->
<!-- generally set to "Guest" or empty value to indicate a private hidden space. -->
<!-- see org.alfresco.service.cmr.security.PermissionService for allowed values -->
<home-space-permission>Guest</home-space-permission>
<!-- the URL to the client Help file -->
<help-url>http://www.alfresco.org/mediawiki/index.php/Client_Help</help-url>
<!-- the type of edit link to use, NOTE: inline editable will always take precedence -->
<!-- can be: http|webdav|cifs -->
<edit-link-type>http</edit-link-type>
</client>
</config>
<config evaluator="node-type" condition="content">
<property-sheet>
<show-property name="name"/>
<show-property name="mimetype" displayLabelId="mimetype" converter="org.alfresco.faces.MimeTypeConverter"/>
<show-property name="title"/>
<show-property name="description"/>
<show-property name="size" displayLabelId="size" converter="org.alfresco.faces.ByteSizeConverter"/>
</property-sheet>
</config>
<config evaluator="node-type" condition="folder">
<property-sheet>
<show-property name="name"/>
<show-property name="description"/>
</property-sheet>
</config>
<config evaluator="node-type" condition="fm:forums">
<property-sheet>
<show-property name="name"/>
<show-property name="description"/>
</property-sheet>
<navigation>
<override from-view-id="/jsp/browse/browse.jsp" to-view-id="/jsp/forums/forums.jsp" />
<override from-outcome="browse" to-view-id="/jsp/forums/forums.jsp" />
<override from-outcome="showSpaceDetails" to-view-id="/jsp/forums/forums-details.jsp" />
<override from-outcome="deleteSpace" to-view-id="/jsp/forums/delete-forums.jsp" />
</navigation>
</config>
<config evaluator="node-type" condition="fm:forum">
<property-sheet>
<show-property name="name"/>
<show-property name="description"/>
<show-property name="fm:status"/>
</property-sheet>
<navigation>
<override from-view-id="/jsp/browse/browse.jsp" to-view-id="/jsp/forums/forum.jsp" />
<override from-outcome="browse" to-view-id="/jsp/forums/forum.jsp" />
<override from-outcome="showSpaceDetails" to-view-id="/jsp/forums/forum-details.jsp" />
<override from-outcome="deleteSpace" to-view-id="/jsp/forums/delete-forum.jsp" />
</navigation>
</config>
<config evaluator="node-type" condition="fm:topic">
<property-sheet>
<show-property name="name"/>
<show-property name="fm:type"/>
</property-sheet>
<navigation>
<override from-view-id="/jsp/browse/browse.jsp" to-view-id="/jsp/forums/topic.jsp" />
<override from-outcome="browse" to-view-id="/jsp/forums/topic.jsp" />
<override from-outcome="showSpaceDetails" to-view-id="/jsp/forums/topic-details.jsp" />
</navigation>
</config>
<config evaluator="node-type" condition="dictionaryModel">
<property-sheet>
<show-property name="modelActive"/>
</property-sheet>
</config>
<!-- Example client config for type defined in exampleModel.xml -->
<config evaluator="node-type" condition="my:sop">
<property-sheet>
<show-property name="name"/>
<show-property name="mimetype" displayLabelId="mimetype" converter="org.alfresco.faces.MimeTypeConverter"/>
<show-property name="title"/>
<show-property name="description"/>
<show-property name="size" displayLabelId="size" converter="org.alfresco.faces.ByteSizeConverter"/>
<show-property name="my:publishedDate"/>
<show-association name="my:signOff"/>
<show-property name="my:authorisedBy"/>
<show-child-association name="my:processSteps"/>
</property-sheet>
</config>
<!-- End Example -->
<config evaluator="aspect-name" condition="complianceable">
<property-sheet>
<show-property name="removeAfter"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="dublincore">
<property-sheet>
<show-property name="publisher"/>
<show-property name="contributor"/>
<show-property name="type"/>
<show-property name="identifier"/>
<show-property name="dcsource"/>
<show-property name="coverage"/>
<show-property name="rights"/>
<show-property name="subject"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="effectivity">
<property-sheet>
<show-property name="from"/>
<show-property name="to"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="summarizable">
<property-sheet>
<show-property name="summary"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="versionable">
<property-sheet>
<show-property name="versionLabel"/>
<show-property name="autoVersion" converter="org.alfresco.faces.BooleanLabelConverter"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="translatable">
<property-sheet>
<show-association name="translations"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="localizable">
<property-sheet>
<show-property name="locale"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="auditable">
<property-sheet>
<show-property name="creator"/>
<show-property name="created" readOnly="true"/>
<show-property name="modifier"/>
<show-property name="modified" readOnly="true"/>
</property-sheet>
</config>
<config evaluator="aspect-name" condition="app:inlineeditable">
<property-sheet>
<show-property name="app:editInline" converter="org.alfresco.faces.BooleanLabelConverter" />
</property-sheet>
</config>
<!-- Example Client Configuration for exposing aspects defined in exampleModel.xml -->
<config evaluator="aspect-name" condition="my:imageClassification">
<property-sheet>
<show-property name="my:width"/>
<show-property name="my:height"/>
<show-property name="my:resolution"/>
</property-sheet>
</config>
<!-- End Example -->
<config evaluator="string-compare" condition="Action Wizards">
<types>
<type name="folder" displayLabelId="space"/>
<type name="content"/>
</types>
<aspects>
<aspect name="generalclassifiable"/>
<aspect name="complianceable"/>
<aspect name="dublincore"/>
<aspect name="effectivity"/>
<aspect name="summarizable"/>
<aspect name="versionable"/>
<!-- <aspect name="templatable"/> -->
<aspect name="translatable"/>
<aspect name="localizable"/>
<!-- Example configuration to demonstrate how to expose aspect from exampleModel.xml -->
<!-- <aspect name="my:imageClassification"/> -->
</aspects>
<transformers>
<transformer name="text/html"/>
<transformer name="application/pdf"/>
<transformer name="text/plain"/>
<transformer name="text/xml"/>
<transformer name="application/x-shockwave-flash"/>
<transformer name="image/gif"/>
<transformer name="image/jpeg"/>
</transformers>
<image-transformers>
<transformer name="image/gif"/>
<transformer name="image/jpeg"/>
<transformer name="image/png"/>
</image-transformers>
</config>
<config evaluator="string-compare" condition="Custom Content Types">
<content-types>
<!-- <type name="my:sop" /> -->
<type name="cm:dictionaryModel"/>
</content-types>
</config>
<config evaluator="string-compare" condition="Custom Folder Types">
<folder-types>
<type name="fm:forums" icon="/images/icons/forums_large.gif" descriptionMsgId="forums_desc" />
</folder-types>
</config>
</alfresco-config>

93
project-build.xml Normal file
View File

@@ -0,0 +1,93 @@
<project name="web-client" default="build">
<path id="path.common" path="${basedir}/../../common"/>
<property name="dir.common" refid="path.common"/>
<import file="${dir.common}/common.xml"/>
<!-- we want to build a WAR file in this project -->
<target name="package" depends="package-war" />
<!-- copy the template web.xml and replace the "@facesconfig@" token with list of faces config files -->
<target name="generate-web-xml" depends="init">
<copy file="${dir.src.webinf}/${file.name.war.template}" tofile="${dir.src.webinf}/web.xml" overwrite="yes" />
<replace file="${dir.src.webinf}/web.xml" token="@facesconfig@" value="${files.faces.config}" />
</target>
<!-- override the common assemble-war target -->
<target name="assemble-war" depends="common.assemble-war, generate-web-xml">
<fail unless="server" message="You must supply a value for the 'server' property to indicate which WAR to build" />
<condition property="isTomcat">
<equals arg1="${server}" arg2="tomcat" casesensitive="false" trim="yes"/>
</condition>
<condition property="isJBoss">
<equals arg1="${server}" arg2="jboss" casesensitive="false" trim="yes"/>
</condition>
<echo level="info">isTomcat = ${isTomcat}</echo>
<echo level="info">isJBoss = ${isJBoss}</echo>
<antcall target="assemble-war-common" />
<antcall target="assemble-war-tomcat" />
<antcall target="assemble-war-jboss" />
</target>
<target name="assemble-war-common">
<copy todir="${dir.assemble}/WEB-INF">
<fileset dir="${dir.project.installer}" includes="licenses/**" />
<fileset dir="${dir.project.remoteapi}/source/web/WEB-INF"/>
</copy>
<copy todir="${dir.assemble}/WEB-INF/lib">
<fileset dir="${dir.common.lib}/jibx" includes="*.jar" />
<fileset dir="${dir.common.lib}/openoffice" includes="*.jar" />
<fileset dir="${dir.common.lib}/jmagick" includes="*.jar" />
<fileset dir="${dir.common.lib}/commons" includes="*.jar" />
<fileset dir="${dir.common.lib}/jgroups" includes="*.jar" />
<fileset dir="${dir.common.lib}/treecache" includes="*.jar" />
<fileset dir="${dir.common.lib}/swarmcache" includes="*.jar" />
<fileset dir="${dir.project.core}/build/dist" includes="${dir.name.core}.jar" />
<fileset dir="${dir.project.repository}/build/dist" includes="${dir.name.repository}.jar" />
<fileset dir="${dir.project.remoteapi}/build/dist" includes="${dir.name.remoteapi}.jar" />
</copy>
<copy todir="${dir.assemble}/wsdl">
<fileset dir="${dir.project.remoteapi}/source/wsdl" />
</copy>
</target>
<target name="assemble-war-tomcat" if="isTomcat">
<!-- remove the jboss specific stuff from WEB-INF -->
<delete>
<fileset dir="${dir.assemble}/WEB-INF" includes="${webinf.delete.tomcat}" />
</delete>
<!-- add config files to WEB-INF/classes -->
<copy todir="${dir.assemble}/WEB-INF/classes">
<fileset dir="${dir.config.repository}"/>
<fileset dir="${dir.config.webclient}"/>
</copy>
<copy todir="${dir.assemble}/WEB-INF/classes" file="${dir.project.core}/source/java/log4j.properties" />
</target>
<target name="assemble-war-jboss" if="isJBoss">
<!-- remove the JARs that cause problems in JBoss -->
<delete>
<fileset dir="${dir.assemble}/WEB-INF/lib" includes="${webinf.lib.delete.jboss}" />
</delete>
<!-- remove existing config files -->
<delete dir="${dir.deploy.jboss}/../conf/alfresco" quiet="yes"/>
<!-- push externally visible config files into conf directory -->
<copy todir="${dir.deploy.jboss}/../conf" >
<fileset dir="${dir.config.repository}"/>
<fileset dir="${dir.config.webclient}"/>
</copy>
</target>
<target name="clean" depends="common.clean" description="Cleans all the normal files plus web.xml">
<delete file="${dir.src.webinf}/web.xml" />
</target>
</project>

View File

@@ -0,0 +1,4 @@
file.name.war=alfresco.war
javadoc.title.window=Alfresco Web Client API
javadoc.title.document=Alfresco Web Client API Specification

4
project.properties Normal file
View File

@@ -0,0 +1,4 @@
webinf.delete.tomcat=jboss*.xml,portlet*.xml,alfresco-pages.xml
webinf.lib.delete.jboss=log4j-1.2.8.jar,portlet-api-lib.jar
files.faces.config=/WEB-INF/faces-config-navigation.xml,/WEB-INF/faces-config-common.xml,/WEB-INF/faces-config-repo.xml,/WEB-INF/faces-config-zoo.xml

View File

@@ -0,0 +1,85 @@
/*
* 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 jsftest;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Object that can be used as a backing bean for components in the zoo
*
* @author gavinc
*/
public class DummyBean
{
private static Log logger = LogFactory.getLog(DummyBean.class);
private String name;
private Properties properties;
public DummyBean()
{
this.properties = new Properties();
this.properties.put("one", "This is 1");
this.properties.put("two", "This is 2");
this.properties.put("three", "This is 3");
this.properties.put("four", "This is 4");
}
public Properties getProperties()
{
return this.properties;
}
/**
* @return Returns the name.
*/
public String getName()
{
return name;
}
/**
* @param name The name to set.
*/
public void setName(String name)
{
this.name = name;
}
/**
* @see java.lang.Object#toString()
*/
public String toString()
{
StringBuilder builder = new StringBuilder(super.toString());
builder.append(" (name=").append(this.name);
builder.append(" properties=").append(this.properties).append(")");
return builder.toString();
}
/**
* Method to call on form submit buttons
*/
public void submit()
{
if (logger.isDebugEnabled())
logger.debug("Submit called on DummyBean, state = " + toString());
}
}

View File

@@ -0,0 +1,100 @@
/*
* 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 jsftest;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import javax.faces.event.ActionEvent;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.UIBreadcrumb;
import org.apache.log4j.Logger;
/**
* @author kevinr
*/
public class TestList
{
/**
* Constructor
*/
public TestList()
{
// Create test data rows
Calendar date = new GregorianCalendar(1999, 1, 5);
rows.add(new TestRow("monkey", 5, true, 0.1f, date.getTime()));
date = new GregorianCalendar(2000, 12, 5);
rows.add(new TestRow("biscuit", 15, true, 0.2f, date.getTime()));
date = new GregorianCalendar(1999, 11, 15);
rows.add(new TestRow("HORSEY", 23, false, 0.333f, date.getTime()));
date = new GregorianCalendar(2003, 11, 11);
rows.add(new TestRow("thing go here", 5123, true, 0.999f, date.getTime()));
date = new GregorianCalendar(1999, 2, 3);
rows.add(new TestRow("I like docs", -5, false, 0.333f, date.getTime()));
date = new GregorianCalendar(2005, 1, 1);
rows.add(new TestRow("Document", 1235, false, 12.0f, date.getTime()));
date = new GregorianCalendar(1998, 8, 8);
rows.add(new TestRow("1234567890", 52, false, 5.0f, date.getTime()));
date = new GregorianCalendar(1997, 9, 30);
rows.add(new TestRow("space", 77, true, 17.5f, date.getTime()));
date = new GregorianCalendar(2001, 7, 15);
rows.add(new TestRow("House", 12, true, 0.4f, date.getTime()));
date = new GregorianCalendar(2002, 5, 28);
rows.add(new TestRow("Baboon", 14, true, -0.888f, date.getTime()));
date = new GregorianCalendar(2003, 11, 11);
rows.add(new TestRow("Woof", 0, true, 0.0f, date.getTime()));
}
public List getRows()
{
return this.rows;
}
public void clickBreadcrumb(ActionEvent event)
{
if (event.getComponent() instanceof UIBreadcrumb)
{
s_logger.debug("clickBreadcrumb action listener called, path now: " + ((UIBreadcrumb)event.getComponent()).getValue());
}
}
public void clickActionLink(ActionEvent event)
{
s_logger.debug("clickActionLink");
}
public void clickNameLink(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String value = params.get("name");
if (value != null)
{
s_logger.debug("clicked item in list: " + value);
}
}
private final static Logger s_logger = Logger.getLogger(TestList.class);
private List<TestRow> rows = new ArrayList<TestRow>();;
}

View File

@@ -0,0 +1,79 @@
/*
* 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 jsftest;
import java.util.Date;
/**
* @author kevinr
*/
public class TestRow
{
/**
* Test a row bean with various data types
*/
public TestRow(String name, int count, boolean valid, float relevance, Date created)
{
this.name = name;
this.count = count;
this.valid = valid;
this.relevance = relevance;
this.created = created;
}
public String getName()
{
return name;
}
public int getCount()
{
return count;
}
public boolean getValid()
{
return valid;
}
public float getRelevance()
{
return relevance;
}
public Date getCreated()
{
return created;
}
public void setCreated(Date date)
{
this.created = date;
}
public TestRow getObject()
{
return this;
}
private String name;
private int count;
private boolean valid;
private float relevance;
private Date created;
}

View File

@@ -0,0 +1,222 @@
/*
* 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 jsftest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.faces.model.SelectItem;
/**
* Class representing a single User bean instance.
*
* @author kevinr
*/
public class User implements Cloneable
{
public User()
{
setRoles(new ArrayList<String>(4));
}
public User(String username, String password, String name, String[] roles, Date joined)
{
setUsername(username);
setPassword(password);
setName(name);
setDateJoined(joined);
List<String> rolesList = new ArrayList<String>(roles.length);
for (int i=0; i<roles.length; i++)
{
rolesList.add(roles[i]);
}
setRoles(rolesList);
}
/**
* Private copy constructor
*
* @param u User to clone
*/
private User(User u)
{
setUsername(u.getUsername());
setPassword(u.getPassword());
setName(u.getName());
setDateJoined(u.getDateJoined());
setRoles(new ArrayList<String>(u.getRoles()));
}
/**
* @see java.lang.Object#clone()
*/
protected Object clone() throws CloneNotSupportedException
{
// invoke copy constructor
return new User(this);
}
/**
* Get the username
*
* @return the username
*/
public String getUsername()
{
return m_username;
}
/**
* Set the username
*
* @param username the username
*/
public void setUsername(String username)
{
m_username = username;
}
/**
* Get the name
*
* @return the name
*/
public String getName()
{
return m_name;
}
/**
* Set the name
*
* @param name the name
*/
public void setName(String name)
{
m_name = name;
}
/**
* Get the roles
*
* @return the roles
*/
public List<String> getRoles()
{
return m_roles;
}
/**
* Set the roles
*
* @param roles the roles
*/
public void setRoles(List<String> roles)
{
m_roles = roles;
}
/**
* Get the password
*
* @return the password
*/
public String getPassword()
{
return m_password;
}
/**
* Set the password
*
* @param password the password
*/
public void setPassword(String password)
{
m_password = password;
}
/**
* Get the All Roles List
*
* @return the allRolesList
*/
public List getAllRolesList()
{
return m_allRolesList;
}
/**
* Set the allRolesList
*
* @param allRolesList the allRolesList
*/
public void setAllRolesList(List<SelectItem> allRolesList)
{
m_allRolesList = allRolesList;
}
/**
* Get the dateJoined
*
* @return the dateJoined
*/
public Date getDateJoined()
{
return m_dateJoined;
}
/**
* Set the dateJoined
*
* @param dateJoined the dateJoined
*/
public void setDateJoined(Date dateJoined)
{
m_dateJoined = dateJoined;
}
/** the allRolesList enum list */
private static List<SelectItem> m_allRolesList = new ArrayList<SelectItem>(8);
static
{
m_allRolesList.add(new SelectItem("admin", "Administrator"));
m_allRolesList.add(new SelectItem("superuser", "Super User"));
m_allRolesList.add(new SelectItem("dev", "Developer"));
m_allRolesList.add(new SelectItem("qa", "QA"));
m_allRolesList.add(new SelectItem("standard", "Basic User"));
}
/** the password */
private String m_password;
/** the username */
private String m_username;
/** the name */
private String m_name;
/** the roles */
private List<String> m_roles;
/** the date joined */
private Date m_dateJoined;
}

View File

@@ -0,0 +1,302 @@
/*
* 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 jsftest;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIParameter;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.validator.ValidatorException;
import org.apache.log4j.Logger;
/**
* JSF Managed Bean. Provides the backing for the userlist.jsp view. The view uses
* the datatable control to bind to the List of User bean objects. Implements the
* action events called by the view when the user clicks the Edit link or Add button.
*
* @author kevinr
*/
public class UserListBean
{
// ===========================================================================
// Construction
public UserListBean()
{
Calendar date = new GregorianCalendar(2002, 5, 10);
m_users.add(new User("admin", "admin", "Administrator", new String[] {"admin","superuser"}, date.getTime()));
date = new GregorianCalendar(2001, 7, 10);
m_users.add(new User("kevinr", "kevinr", "Kevin Roast", new String[] {"admin","superuser","dev"}, date.getTime()));
date = new GregorianCalendar(2003, 8, 15);
m_users.add(new User("gavinc", "gavinc", "Gavin Cornwell", new String[] {"superuser","dev"}, date.getTime()));
date = new GregorianCalendar(2003, 1, 1);
m_users.add(new User("stever", "stever", "Steve Rigby", new String[] {"superuser","qa"}, date.getTime()));
}
// ===========================================================================
// Bean methods
public List getUsers()
{
return m_users;
}
public void setUsers(List<User> users)
{
m_users = users;
}
/**
* Get the users list as a wrapped DataModel object
*
* @return DataModel for use by the data-table components
*/
public DataModel getUsersModel()
{
if (m_usersModel == null)
{
m_usersModel = new ListDataModel();
m_usersModel.setWrappedData(m_users);
}
return m_usersModel;
}
public User getUser()
{
return m_currentUser;
}
public void setUser(User user)
{
m_currentUser = user;
}
/**
* Get the isNewUser
*
* @return the isNewUser
*/
public boolean getIsNewUser()
{
return m_isNewUser;
}
/**
* Set the isNewUser
*
* @param isNewUser the isNewUser
*/
public void setIsNewUser(boolean isNewUser)
{
m_isNewUser = isNewUser;
}
/**
* Get the rolesOutputText
*
* @return the rolesOutputText
*/
public HtmlOutputText getRolesOutputText()
{
return m_rolesOutputText;
}
/**
* Set the rolesOutputText
*
* @param rolesOutputText the rolesOutputText component
*/
public void setRolesOutputText(HtmlOutputText rolesOutputText)
{
m_rolesOutputText = rolesOutputText;
}
// ===========================================================================
// Action event methods
/**
* Edit user action event listener
*
* Specified directly on the appropriate tag such as commandLink or commandButton
* e.g. actionListener="#{UserListBean.editUser}"
*
* This listener cannot directly affect the navigation of the page - the command
* tag has an "action" attribute of which the default handler will use the outcome
* from the faces-config.xml by default or call a specifid controller method
* returning the String outcome as usual.
*/
public void editUser(ActionEvent event)
{
s_logger.debug("*****USERLIST: " + ((UIParameter)event.getComponent().findComponent("userId")).getValue().toString());
// Get the username from the "param" tag component we added as a nested tag
// to the command tag that fired this event.
// So we can have a key to work out which item was clicked in the data table
String usernameId = ((UIParameter)event.getComponent().findComponent("userId")).getValue().toString();
// It is also possible to get the relevent row from the DataModel we created
// wrapping our users list. But this is a weak solution as models which then
// potentially sort or page data may not provide the correct row index.
// e.g.
// m_usersModel.getWrappedData().get(m_usersModel.getRowIndex());
for (Iterator i=m_users.iterator(); i.hasNext(); /**/)
{
User user = (User)i.next();
if (user.getUsername().equals(usernameId))
{
// set the user as current so we know which one to edit etc.
try
{
setUser((User)user.clone());
setIsNewUser(false);
}
catch (CloneNotSupportedException e)
{
// will not happen - clone is supported for our own types
}
}
}
}
/**
* OK button action handler
*
* @return outcome view name
*/
public void editUserOK(ActionEvent event)
{
s_logger.debug("*****USERLIST: persisting user: " + getUser().getUsername());
for (int i=0; i<m_users.size(); i++)
{
User user = (User)m_users.get(i);
if (user.getUsername().equals(getUser().getUsername()))
{
// found modified user - persist changes
m_users.set(i, getUser());
m_usersModel = null;
break;
}
}
}
/**
* Add user action event listener
*/
public void addUser(ActionEvent event)
{
// create a blank user template
setUser(new User());
setIsNewUser(true);
}
/**
* OK button action handler
*
* @return outcome view name
*/
public void addUserOK(ActionEvent event)
{
// persist new user details
s_logger.debug("*****USERLIST: creating user: " + getUser().getUsername());
m_users.add(getUser());
m_usersModel = null;
}
/**
* Example of a value changed event handler
* NOTE: Value changed events do not submit the form directly, either a command
* button or link submits the form or can be done manually with Javascript
*/
public void roleValueChanged(ValueChangeEvent event)
{
s_logger.debug("*****USERLIST: Value change from: " + event.getOldValue() + " to: " + event.getNewValue());
// example of the use of a direct component binding
// in the JSP page, a outputText tag has used binding='beanmethod' so we
// can now programatically modify the component as required
if (m_rolesOutputText != null)
{
m_rolesOutputText.setValue(getUser().getRoles().toString());
}
// An alternative to using the component binding would be to lookup the
// component via it's component Id:
// HtmlOutputText comp = (HtmlOutputText)event.getComponent().findComponent("roles-text");
// comp.setValue(...);
// The attributes of a component are all stored in a Map, the Map features
// attribute-property transparency which means typed attributes can be get/set
// directly without using casts as the appropriate getters/setters will be
// called for you by the framework.
// comp.getAttributes().put("style", "color:red");
}
// ===========================================================================
// Validator methods
/**
* Example of a specific validation method. Required as the basic validator
* child tags are not sufficient for anything beyond very simple length checks etc.
*/
public void validateUsername(FacesContext context, UIComponent component, Object value)
throws ValidatorException
{
String username = (String)value;
if (username.length() < 5 || username.length() > 12)
{
String err = "Username must be between 5 and 12 characters in length.";
throw new ValidatorException(new FacesMessage(err));
}
else if (username.indexOf(' ') != -1 || username.indexOf('\t') != -1)
{
String err = "Username cannot contain space or whitespace characters.";
throw new ValidatorException(new FacesMessage(err));
}
}
// ===========================================================================
// Private data
private List<User> m_users = new ArrayList<User>();
private DataModel m_usersModel = null;
private User m_currentUser = null;
private boolean m_isNewUser = false;
/** the HTMLOutputText component */
private HtmlOutputText m_rolesOutputText = null;
protected final static Logger s_logger = Logger.getLogger(UserListBean.class);
}

View File

@@ -0,0 +1,35 @@
/*
* 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 jsftest;
/**
* Managed bean that provides action handlers to navigate around the component zoo
*
* @author gavinc
*/
public class ZooService
{
public String showPropertyZoo()
{
return "showPropertyZoo";
}
public String showPropertyZoo2()
{
return "showPropertyZoo2";
}
}

View File

@@ -0,0 +1,256 @@
/*
* 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 jsftest.repository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Class to represent a basic data dictionary service
*
* @author gavinc
*/
public class DataDictionary
{
private Map types;
public DataDictionary()
{
this.types = new HashMap();
// setup the dictionary
Property name = new Property("name", "string", "Name", false);
Property desc = new Property("description", "string", "Description" , false);
Property created = new Property("created", "datetime", "Created Date", true);
Property modified = new Property("modified", "datetime", "Modified Date", false);
Property keywords = new Property("keywords", "string[]", "Keywords", false);
MetaData base = new MetaData("base");
base.addProperty(name);
base.addProperty(desc);
base.addProperty(created);
base.addProperty(modified);
base.addProperty(keywords);
Property sopid = new Property("sopId", "string", "SOP ID", true);
Property effective = new Property("effective", "datetime", "Effective Date", false);
Property approved = new Property("approved", "boolean", "Approved", false);
Property latestVersion = new Property("latestversion", "string", "Latest Version", true);
MetaData sop = new MetaData("SOP");
sop.setProperties(base.getProperties());
sop.addProperty(sopid);
sop.addProperty(effective);
sop.addProperty(approved);
// add an aspect and the associated property
sop.addAspect("versionable");
sop.addProperty(latestVersion);
this.types.put(base.getTypeName(), base);
this.types.put(sop.getTypeName(), sop);
}
public MetaData getMetaData(String type)
{
return (MetaData)this.types.get(type);
}
/**
* @return Returns the types.
*/
public Map getTypes()
{
return this.types;
}
// *********************
// *** Inner classes ***
// *********************
/**
* Represents the meta data of an object
* @author gavinc
*/
public class MetaData
{
private Map propertiesMap;
private List properties;
private String typeName;
private List aspects;
public MetaData(String typeName)
{
this.properties = new ArrayList();
this.propertiesMap = new HashMap();
this.aspects = new ArrayList();
this.typeName = typeName;
}
/**
* Adds a property to the meta data object
*
* @author gavinc
*/
public void addProperty(Property property)
{
this.properties.add(property);
this.propertiesMap.put(property.getName(), property);
}
/**
* @return Returns the properties.
*/
public List getProperties()
{
return this.properties;
}
/**
* @param properties The properties to set.
*/
public void setProperties(List properties)
{
this.properties.clear();
this.propertiesMap.clear();
Iterator iter = properties.iterator();
while (iter.hasNext())
{
Property prop = (Property)iter.next();
this.properties.add(prop);
this.propertiesMap.put(prop.getName(), prop);
}
}
public Map getPropertiesMap()
{
return this.propertiesMap;
}
public List getAspects()
{
return this.aspects;
}
public void addAspect(String aspect)
{
this.aspects.add(aspect);
}
/**
* @return Returns the typeName.
*/
public String getTypeName()
{
return this.typeName;
}
}
/**
* Represents a property on an object
* @author gavinc
*/
public class Property
{
private String name;
private String type;
private String displayName;
private boolean readOnly;
/**
* @param name
* @param type
* @param readOnly
*/
public Property(String name, String type, String displayName, boolean readOnly)
{
this.name = name;
this.type = type;
this.displayName = displayName;
this.readOnly = readOnly;
}
/**
* @return Returns the name.
*/
public String getName()
{
return this.name;
}
/**
* @param name The name to set.
*/
public void setName(String name)
{
this.name = name;
}
/**
* @return Returns the type.
*/
public String getType()
{
return this.type;
}
/**
* @param type The type to set.
*/
public void setType(String type)
{
this.type = type;
}
/**
* @return Returns the displayName.
*/
public String getDisplayName()
{
return this.displayName;
}
/**
* @param displayName The displayName to set.
*/
public void setDisplayName(String displayName)
{
this.displayName = displayName;
}
/**
* @return Returns the readOnly.
*/
public boolean isReadOnly()
{
return this.readOnly;
}
/**
* @param readOnly The readOnly to set.
*/
public void setReadOnly(boolean readOnly)
{
this.readOnly = readOnly;
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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 jsftest.repository;
import java.io.Serializable;
/**
* Mock NodeRef object that comes from the Mock NodeService API.
*
* @author gavinc
*/
public class NodeRef implements Serializable
{
private static final long serialVersionUID = 3833183614468175153L;
private String id;
public NodeRef(String id)
{
this.id = id;
}
/**
* @return Returns the id.
*/
public String getId()
{
return id;
}
}

View File

@@ -0,0 +1,104 @@
/*
* 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 jsftest.repository;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Mock NodeService API
*
* @author gavinc
*/
public class NodeService
{
private static Log logger = LogFactory.getLog(NodeService.class);
public static NodeRef getNodeRef(String path)
{
return new NodeRef(path);
}
public static String getType(NodeRef nodeRef)
{
String id = nodeRef.getId();
String type = null;
if (id.equalsIgnoreCase("/gav.doc") ||
id.equalsIgnoreCase("/kev.txt"))
{
type = "base";
}
else if (id.equalsIgnoreCase("/sop.txt"))
{
type = "SOP";
}
return type;
}
public static Map getProperties(NodeRef nodeRef)
{
String id = nodeRef.getId();
Map properties = null;
if (id.equalsIgnoreCase("/gav.doc"))
{
properties = createProperties("Gav", "Gavs Object",
new String[] {"gav", "gadget", "gibbon"}, null);
}
else if (id.equalsIgnoreCase("/kev.txt"))
{
properties = createProperties("Kev", "Kevs Object",
new String[] {"kev", "monkey"}, null);
}
else if (id.equalsIgnoreCase("/sop.txt"))
{
properties = createProperties("SOP", "A manufacturing SOP",
new String[] {"sop", "manufacturing"}, "sop1");
}
return properties;
}
private static Map createProperties(String name, String desc,
String[] keywords, String sop)
{
HashMap props = new HashMap();
Date date = new Date();
props.put("name", name);
props.put("description", desc);
props.put("keywords", keywords);
props.put("created", date);
props.put("modified", date);
if (sop != null)
{
props.put("sopId", sop);
props.put("effective", date);
props.put("approved", new Boolean(true));
props.put("latestversion", "1.6");
}
return props;
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the GNU Lesser General Public License as
* published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.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.web.app;
import javax.faces.application.NavigationHandler;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import org.alfresco.config.Config;
import org.alfresco.config.ConfigService;
import org.alfresco.web.bean.NavigationBean;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.config.NavigationConfigElement;
import org.alfresco.web.config.NavigationElementReader;
import org.alfresco.web.config.NavigationResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.jsf.FacesContextUtils;
/**
* @author gavinc
*/
public class AlfrescoNavigationHandler extends NavigationHandler
{
private final static Log logger = LogFactory.getLog(AlfrescoNavigationHandler.class);
// The original navigation handler
private NavigationHandler origHandler;
/**
* Default constructor
*
* @param origHandler The original navigation handler
*/
public AlfrescoNavigationHandler(NavigationHandler origHandler)
{
super();
this.origHandler = origHandler;
}
/**
* @see javax.faces.application.NavigationHandler#handleNavigation(javax.faces.context.FacesContext, java.lang.String, java.lang.String)
*/
@Override
public void handleNavigation(FacesContext context, String fromAction, String outcome)
{
if (logger.isDebugEnabled())
logger.debug("handleNavigation (fromAction=" + fromAction + ", outcome=" + outcome + ")");
boolean useOriginalNavHandler = true;
String finalOutcome = outcome;
String viewId = context.getViewRoot().getViewId();
if (logger.isDebugEnabled())
logger.debug("Current view id: " + viewId);
NavigationBean navBean = (NavigationBean)context.getExternalContext().
getSessionMap().get("NavigationBean");
// only continue if we have some dispatching context
if (navBean != null && navBean.getDispatchContextNode() != null)
{
Node node = navBean.getDispatchContextNode();
if (logger.isDebugEnabled())
logger.debug("Found node in dispatch context: " + node);
// see if there is any navigation config for the node type
ConfigService configSvc = (ConfigService)FacesContextUtils.getRequiredWebApplicationContext(
context).getBean(Application.BEAN_CONFIG_SERVICE);
Config nodeConfig = configSvc.getConfig(node);
NavigationConfigElement navigationCfg = (NavigationConfigElement)nodeConfig.
getConfigElement(NavigationElementReader.ELEMENT_NAVIGATION);
if (navigationCfg != null)
{
// see if there is config for the current view state
NavigationResult navResult = navigationCfg.getOverride(viewId, outcome);
if (navResult != null)
{
if (logger.isDebugEnabled())
logger.debug("Found navigation config: " + navResult);
if (navResult.isOutcome())
{
finalOutcome = navResult.getResult();
}
else
{
String newViewId = navResult.getResult();
if (newViewId.equals(viewId) == false)
{
useOriginalNavHandler = false;
if (logger.isDebugEnabled())
logger.debug("Dispatching to new view id: " + newViewId);
ViewHandler viewHandler = context.getApplication().getViewHandler();
UIViewRoot viewRoot = viewHandler.createView(context, newViewId);
viewRoot.setViewId(newViewId);
context.setViewRoot(viewRoot);
context.renderResponse();
}
else
{
if (logger.isDebugEnabled())
logger.debug("New view id is the same as the current one so setting outcome to null");
finalOutcome = null;
}
}
}
else if (logger.isDebugEnabled())
{
logger.debug("No override configuration found for current view or outcome");
}
}
else if (logger.isDebugEnabled())
{
logger.debug("No navigation configuration found for node");
}
// reset the dispatch context
navBean.resetDispatchContext();
}
else if (logger.isDebugEnabled())
{
logger.debug("No dispatch context found");
}
// do the appropriate navigation handling
if (useOriginalNavHandler)
{
if (logger.isDebugEnabled())
logger.debug("Passing outcome '" + finalOutcome + "' to original navigation handler");
this.origHandler.handleNavigation(context, fromAction, finalOutcome);
}
}
}

View File

@@ -0,0 +1,662 @@
/*
* 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.web.app;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import javax.faces.context.FacesContext;
import javax.portlet.PortletContext;
import javax.portlet.PortletSession;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.alfresco.config.ConfigService;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.importer.ImporterBootstrap;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.web.app.servlet.AuthenticationHelper;
import org.alfresco.web.bean.ErrorBean;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.config.ServerConfigElement;
import org.apache.commons.logging.Log;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.jsf.FacesContextUtils;
/**
* Utilities class
*
* @author gavinc
*/
public class Application
{
private static final String LOCALE = "locale";
public static final String BEAN_CONFIG_SERVICE = "configService";
public static final String BEAN_DATA_DICTIONARY = "dataDictionary";
public static final String BEAN_IMPORTER_BOOTSTRAP = "importerBootstrap";
public static final String MESSAGE_BUNDLE = "alfresco.messages.webclient";
private static boolean inPortalServer = true;
private static StoreRef repoStoreRef;
private static String rootPath;
private static String companyRootId;
private static String companyRootDescription;
private static String glossaryFolderName;
private static String spaceTemplatesFolderName;
private static String contentTemplatesFolderName;
/**
* Private constructor to prevent instantiation of this class
*/
private Application()
{
}
/**
* Sets whether this application is running inside a portal server
*
* @param inPortal true to indicate the application is running as a portlet
*/
public static void setInPortalServer(boolean inPortal)
{
inPortalServer = inPortal;
}
/**
* Determines whether the server is running in a portal
*
* @return true if we are running inside a portal server
*/
public static boolean inPortalServer()
{
return inPortalServer;
}
/**
* Handles errors thrown from servlets
*
* @param servletContext The servlet context
* @param request The HTTP request
* @param response The HTTP response
* @param error The exception
* @param logger The logger
*/
public static void handleServletError(ServletContext servletContext, HttpServletRequest request,
HttpServletResponse response, Throwable error, Log logger, String returnPage)
throws IOException, ServletException
{
// get the error bean from the session and set the error that occurred.
HttpSession session = request.getSession();
ErrorBean errorBean = (ErrorBean)session.getAttribute(ErrorBean.ERROR_BEAN_NAME);
if (errorBean == null)
{
errorBean = new ErrorBean();
session.setAttribute(ErrorBean.ERROR_BEAN_NAME, errorBean);
}
errorBean.setLastError(error);
errorBean.setReturnPage(returnPage);
// try and find the configured error page
boolean errorShown = false;
String errorPage = getErrorPage(servletContext);
if (errorPage != null)
{
if (logger.isDebugEnabled())
logger.debug("An error has occurred, redirecting to error page: " + errorPage);
if (response.isCommitted() == false)
{
errorShown = true;
response.sendRedirect(request.getContextPath() + errorPage);
}
else
{
if (logger.isDebugEnabled())
logger.debug("Response is already committed, re-throwing error");
}
}
else
{
if (logger.isDebugEnabled())
logger.debug("No error page defined, re-throwing error");
}
// if we could not show the error page for whatever reason, re-throw the error
if (!errorShown)
{
if (error instanceof IOException)
{
throw (IOException)error;
}
else if (error instanceof ServletException)
{
throw (ServletException)error;
}
else
{
throw new ServletException(error);
}
}
}
/**
* Retrieves the configured error page for the application
*
* @param servletContext The servlet context
* @return The configured error page or null if the configuration is missing
*/
public static String getErrorPage(ServletContext servletContext)
{
return getErrorPage(WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext));
}
/**
* Retrieves the configured error page for the application
*
* @param portletContext The portlet context
* @return
*/
public static String getErrorPage(PortletContext portletContext)
{
return getErrorPage((WebApplicationContext)portletContext.getAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE));
}
/**
* Retrieves the configured login page for the application
*
* @param servletContext The servlet context
* @return The configured login page or null if the configuration is missing
*/
public static String getLoginPage(ServletContext servletContext)
{
return getLoginPage(WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext));
}
/**
* Retrieves the configured login page for the application
*
* @param portletContext The portlet context
* @return
*/
public static String getLoginPage(PortletContext portletContext)
{
return getLoginPage((WebApplicationContext)portletContext.getAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE));
}
/**
* @return Returns the User object representing the currently logged in user
*/
public static User getCurrentUser(HttpSession session)
{
return (User)session.getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
}
/**
* @return Returns the User object representing the currently logged in user
*/
public static User getCurrentUser(FacesContext context)
{
return (User)context.getExternalContext().getSessionMap().get(AuthenticationHelper.AUTHENTICATION_USER);
}
/**
* @return Returns the repository store URL (retrieved from config service)
*/
public static StoreRef getRepositoryStoreRef(ServletContext context)
{
return getRepositoryStoreRef(WebApplicationContextUtils.getRequiredWebApplicationContext(context));
}
/**
* @return Returns the repository store URL (retrieved from config service)
*/
public static StoreRef getRepositoryStoreRef(FacesContext context)
{
return getRepositoryStoreRef(FacesContextUtils.getRequiredWebApplicationContext(context));
}
/**
* @return Returns id of the company root
*/
public static String getCompanyRootId()
{
return companyRootId;
}
/**
* Sets the company root id. This is setup by the ContextListener.
*
* @param id The company root id
*/
public static void setCompanyRootId(String id)
{
companyRootId = id;
}
/**
* @return Returns the root path for the application (retrieved from config service)
*/
public static String getRootPath(ServletContext context)
{
return getRootPath(WebApplicationContextUtils.getRequiredWebApplicationContext(context));
}
/**
* @return Returns the root path for the application (retrieved from config service)
*/
public static String getRootPath(FacesContext context)
{
return getRootPath(FacesContextUtils.getRequiredWebApplicationContext(context));
}
/**
* @return Returns the glossary folder name (retrieved from config service)
*/
public static String getGlossaryFolderName(ServletContext context)
{
return getGlossaryFolderName(WebApplicationContextUtils.getRequiredWebApplicationContext(context));
}
/**
* @return Returns the glossary folder name (retrieved from config service)
*/
public static String getGlossaryFolderName(FacesContext context)
{
return getGlossaryFolderName(FacesContextUtils.getRequiredWebApplicationContext(context));
}
/**
* @return Returns the Space templates folder name (retrieved from config service)
*/
public static String getSpaceTemplatesFolderName(ServletContext context)
{
return getSpaceTemplatesFolderName(WebApplicationContextUtils.getRequiredWebApplicationContext(context));
}
/**
* @return Returns the Space templates folder name (retrieved from config service)
*/
public static String getSpaceTemplatesFolderName(FacesContext context)
{
return getSpaceTemplatesFolderName(FacesContextUtils.getRequiredWebApplicationContext(context));
}
/**
* @return Returns the Content templates folder name (retrieved from config service)
*/
public static String getContentTemplatesFolderName(ServletContext context)
{
return getContentTemplatesFolderName(WebApplicationContextUtils.getRequiredWebApplicationContext(context));
}
/**
* @return Returns the Content templates folder name (retrieved from config service)
*/
public static String getContentTemplatesFolderName(FacesContext context)
{
return getContentTemplatesFolderName(FacesContextUtils.getRequiredWebApplicationContext(context));
}
/**
* Set the language locale for the current user context
*
* @param context FacesContext for current user
* @param code The ISO locale code to set
*/
public static void setLanguage(FacesContext context, String code)
{
Locale locale = parseLocale(code);
// set locale for JSF framework usage
context.getViewRoot().setLocale(locale);
// set locale for our framework usage
context.getExternalContext().getSessionMap().put(LOCALE, locale);
// clear the current message bundle - so it's reloaded with new locale
context.getExternalContext().getSessionMap().remove(MESSAGE_BUNDLE);
}
/**
* Set the language locale for the current user session
*
* @param session HttpSession for current user
* @param code The ISO locale code to set
*/
public static void setLanguage(HttpSession session, String code)
{
Locale locale = parseLocale(code);
session.putValue(LOCALE, locale);
session.removeAttribute(MESSAGE_BUNDLE);
}
/**
* @param code Locale code (java format with underscores) to parse
* @return Locale object or default if unable to parse
*/
private static Locale parseLocale(String code)
{
Locale locale = Locale.getDefault();
StringTokenizer t = new StringTokenizer(code, "_");
int tokens = t.countTokens();
if (tokens == 1)
{
locale = new Locale(code);
}
else if (tokens == 2)
{
locale = new Locale(t.nextToken(), t.nextToken());
}
else if (tokens == 3)
{
locale = new Locale(t.nextToken(), t.nextToken(), t.nextToken());
}
return locale;
}
/**
* Return the language Locale for the current user context
*
* @param context FacesContext for the current user
*
* @return Current language Locale set or null if none set
*/
public static Locale getLanguage(FacesContext context)
{
return (Locale)context.getExternalContext().getSessionMap().get(LOCALE);
}
/**
* Return the language Locale for the current user Session.
*
* @param session HttpSession for the current user
*
* @return Current language Locale set or null if none set
*/
public static Locale getLanguage(HttpSession session)
{
return (Locale)session.getAttribute(LOCALE);
}
/**
* Return the language Locale for the current user PortletSession.
*
* @param session PortletSession for the current user
*
* @return Current language Locale set or null if none set
*/
public static Locale getLanguage(PortletSession session)
{
return (Locale)session.getAttribute(LOCALE);
}
/**
* Get the specified I18N message string from the default message bundle for this user
*
* @param context FacesContext
* @param msg Message ID
*
* @return String from message bundle or $$msg$$ if not found
*/
public static String getMessage(FacesContext context, String msg)
{
return getBundle(context).getString(msg);
}
/**
* Get the specified I18N message string from the default message bundle for this user
*
* @param session HttpSession
* @param msg Message ID
*
* @return String from message bundle or $$msg$$ if not found
*/
public static String getMessage(HttpSession session, String msg)
{
return getBundle(session).getString(msg);
}
/**
* Get the specified the default message bundle for this user
*
* @param session HttpSession
*
* @return ResourceBundle for this user
*/
public static ResourceBundle getBundle(HttpSession session)
{
ResourceBundle bundle = (ResourceBundle)session.getAttribute(MESSAGE_BUNDLE);
if (bundle == null)
{
// get Locale from language selected by each user on login
Locale locale = (Locale)session.getAttribute(LOCALE);
if (locale == null)
{
locale = Locale.getDefault();
}
bundle = ResourceBundle.getBundle(MESSAGE_BUNDLE, locale);
if (bundle == null)
{
throw new AlfrescoRuntimeException("Unable to load Alfresco messages bundle: " + MESSAGE_BUNDLE);
}
// apply our wrapper to catch MissingResourceException
bundle = new ResourceBundleWrapper(bundle);
session.setAttribute(MESSAGE_BUNDLE, bundle);
}
return bundle;
}
/**
* Get the specified the default message bundle for this user
*
* @param context FacesContext
*
* @return ResourceBundle for this user
*/
public static ResourceBundle getBundle(FacesContext context)
{
// get the resource bundle for the current locale
// we store the bundle in the users session
// this makes it easy to add a locale per user support later
Map session = context.getExternalContext().getSessionMap();
ResourceBundle bundle = (ResourceBundle)session.get(MESSAGE_BUNDLE);
if (bundle == null)
{
// get Locale from language selected by each user on login
Locale locale = (Locale)session.get(LOCALE);
if (locale == null)
{
locale = Locale.getDefault();
}
bundle = ResourceBundle.getBundle(MESSAGE_BUNDLE, locale);
if (bundle == null)
{
throw new AlfrescoRuntimeException("Unable to load Alfresco messages bundle: " + MESSAGE_BUNDLE);
}
// apply our wrapper to catch MissingResourceException
bundle = new ResourceBundleWrapper(bundle);
session.put(MESSAGE_BUNDLE, bundle);
}
return bundle;
}
/**
* Helper to get the ConfigService instance
*
* @param context FacesContext
*
* @return ConfigService
*/
public static ConfigService getConfigService(FacesContext context)
{
return (ConfigService)FacesContextUtils.getRequiredWebApplicationContext(context).getBean(
Application.BEAN_CONFIG_SERVICE);
}
/**
* Returns the repository store URL (retrieved from config service)
*
* @param context The spring context
* @return The repository store URL to use
*/
private static StoreRef getRepositoryStoreRef(WebApplicationContext context)
{
if (repoStoreRef == null)
{
ImporterBootstrap bootstrap = (ImporterBootstrap)context.getBean(BEAN_IMPORTER_BOOTSTRAP);
repoStoreRef = bootstrap.getStoreRef();
}
return repoStoreRef;
}
/**
* Returns the root path for the application (retrieved from config service)
*
* @param context The spring context
* @return The application root path
*/
private static String getRootPath(WebApplicationContext context)
{
if (rootPath == null)
{
ImporterBootstrap bootstrap = (ImporterBootstrap)context.getBean(BEAN_IMPORTER_BOOTSTRAP);
Properties configuration = bootstrap.getConfiguration();
rootPath = configuration.getProperty("spaces.company_home.childname");
}
return rootPath;
}
/**
* Returns the glossary folder name (retrieved from config service)
*
* @param context The spring context
* @return The glossary folder name
*/
private static String getGlossaryFolderName(WebApplicationContext context)
{
if (glossaryFolderName == null)
{
ImporterBootstrap bootstrap = (ImporterBootstrap)context.getBean(BEAN_IMPORTER_BOOTSTRAP);
Properties configuration = bootstrap.getConfiguration();
glossaryFolderName = configuration.getProperty("spaces.dictionary.childname");
}
return glossaryFolderName;
}
/**
* Returns the Space Templates folder name (retrieved from config service)
*
* @param context The spring context
* @return The templates folder name
*/
private static String getSpaceTemplatesFolderName(WebApplicationContext context)
{
if (spaceTemplatesFolderName == null)
{
ImporterBootstrap bootstrap = (ImporterBootstrap)context.getBean(BEAN_IMPORTER_BOOTSTRAP);
Properties configuration = bootstrap.getConfiguration();
spaceTemplatesFolderName = configuration.getProperty("spaces.templates.childname");
}
return spaceTemplatesFolderName;
}
/**
* Returns the Content Templates folder name (retrieved from config service)
*
* @param context The spring context
* @return The templates folder name
*/
private static String getContentTemplatesFolderName(WebApplicationContext context)
{
if (contentTemplatesFolderName == null)
{
ImporterBootstrap bootstrap = (ImporterBootstrap)context.getBean(BEAN_IMPORTER_BOOTSTRAP);
Properties configuration = bootstrap.getConfiguration();
contentTemplatesFolderName = configuration.getProperty("spaces.templates.content.childname");
}
return contentTemplatesFolderName;
}
/**
* Retrieves the configured error page for the application
*
* @param context The Spring contexr
* @return The configured error page or null if the configuration is missing
*/
private static String getErrorPage(WebApplicationContext context)
{
String errorPage = null;
ConfigService svc = (ConfigService)context.getBean(BEAN_CONFIG_SERVICE);
ServerConfigElement serverConfig = (ServerConfigElement)svc.getGlobalConfig().getConfigElement("server");
if (serverConfig != null)
{
errorPage = serverConfig.getErrorPage();
}
return errorPage;
}
/**
* Retrieves the configured login page for the application
*
* @param context The Spring contexr
* @return The configured login page or null if the configuration is missing
*/
private static String getLoginPage(WebApplicationContext context)
{
String loginPage = null;
ConfigService svc = (ConfigService)context.getBean(BEAN_CONFIG_SERVICE);
ServerConfigElement serverConfig = (ServerConfigElement)svc.getGlobalConfig().getConfigElement("server");
if (serverConfig != null)
{
loginPage = serverConfig.getLoginPage();
}
return loginPage;
}
}

View File

@@ -0,0 +1,263 @@
/*
* 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.web.app;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import javax.transaction.UserTransaction;
import org.alfresco.config.ConfigElement;
import org.alfresco.config.ConfigService;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.app.portlet.AlfrescoFacesPortlet;
import org.alfresco.web.app.servlet.AuthenticationHelper;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* ServletContextListener implementation that initialises the application.
*
* NOTE: This class must appear after the Spring context loader listener
*
* @author gavinc
*/
public class ContextListener implements ServletContextListener, HttpSessionListener
{
private static Log logger = LogFactory.getLog(ContextListener.class);
private static final String ADMIN = "admin";
private static final String ADMIN_FIRSTNAME = "Repository";
private static final String ADMIN_LASTNAME = "Administrator";
private ServletContext servletContext;
/**
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent event)
{
// make sure that the spaces store in the repository exists
this.servletContext = event.getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
ServiceRegistry registry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
TransactionService transactionService = registry.getTransactionService();
NodeService nodeService = registry.getNodeService();
SearchService searchService = registry.getSearchService();
NamespaceService namespaceService = registry.getNamespaceService();
AuthenticationComponent authenticationComponent = (AuthenticationComponent) ctx
.getBean("authenticationComponent");
// repo bootstrap code for our client
UserTransaction tx = null;
NodeRef companySpaceNodeRef = null;
try
{
tx = transactionService.getUserTransaction();
tx.begin();
authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
// get and setup the initial store ref from config
StoreRef storeRef = Repository.getStoreRef(servletContext);
// check the repository exists, create if it doesn't
if (nodeService.exists(storeRef) == false)
{
throw new AlfrescoRuntimeException("Store not created prior to application startup: " + storeRef);
}
// get hold of the root node
NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
// see if the company home space is present
String rootPath = Application.getRootPath(servletContext);
if (rootPath == null)
{
throw new AlfrescoRuntimeException("Root path has not been configured");
}
List<NodeRef> nodes = searchService.selectNodes(rootNodeRef, rootPath, null, namespaceService, false);
if (nodes.size() == 0)
{
throw new AlfrescoRuntimeException("Root path not created prior to application startup: " + rootPath);
}
// Extract company space id and store it in the Application object
companySpaceNodeRef = nodes.get(0);
Application.setCompanyRootId(companySpaceNodeRef.getId());
// check the admin user exists, create if it doesn't
MutableAuthenticationDao dao = (MutableAuthenticationDao) ctx.getBean("alfDaoImpl");
// this is required to setup the ACEGI context before we can check
// for the user
if (!dao.userExists(ADMIN))
{
ConfigService configService = (ConfigService) ctx.getBean(Application.BEAN_CONFIG_SERVICE);
// default to password of "admin" if we don't find config for it
String password = ADMIN;
ConfigElement adminConfig = configService.getGlobalConfig().getConfigElement("admin");
if (adminConfig != null)
{
List<ConfigElement> children = adminConfig.getChildren();
if (children.size() != 0)
{
// try to find the config element for the initial
// password
ConfigElement passElement = children.get(0);
if (passElement.getName().equals("initial-password"))
{
password = passElement.getValue();
}
}
}
// create the Authentication instance for the "admin" user
AuthenticationService authService = (AuthenticationService) ctx.getBean("authenticationService");
authService.createAuthentication(ADMIN, password.toCharArray());
}
PersonService personService = (PersonService) ctx.getBean("personService");
if (!personService.personExists(ADMIN))
{
// create the node to represent the Person instance for the
// admin user
Map<QName, Serializable> props = new HashMap<QName, Serializable>(7, 1.0f);
props.put(ContentModel.PROP_USERNAME, ADMIN);
props.put(ContentModel.PROP_FIRSTNAME, ADMIN_FIRSTNAME);
props.put(ContentModel.PROP_LASTNAME, ADMIN_LASTNAME);
props.put(ContentModel.PROP_HOMEFOLDER, companySpaceNodeRef);
props.put(ContentModel.PROP_EMAIL, "");
props.put(ContentModel.PROP_ORGID, "");
personService.createPerson(props);
}
// set the store's GUEST access if we are allowed to modify permissions
if (!transactionService.isReadOnly())
{
PermissionService permissionService = (PermissionService) ctx.getBean("permissionService");
permissionService.setPermission(rootNodeRef, permissionService.getAllAuthorities(), PermissionService.GUEST, true);
}
// commit the transaction
tx.commit();
}
catch (Throwable e)
{
// rollback the transaction
try
{
if (tx != null)
{
tx.rollback();
}
}
catch (Exception ex) {}
logger.error("Failed to initialise ", e);
throw new AlfrescoRuntimeException("Failed to initialise ", e);
}
finally
{
try
{
authenticationComponent.clearCurrentSecurityContext();
}
catch (Exception ex) {}
}
}
/**
* @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent event)
{
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
Scheduler quartz = (Scheduler) ctx.getBean("schedulerFactory");
try
{
quartz.shutdown(true);
}
catch (SchedulerException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Session created listener
*/
public void sessionCreated(HttpSessionEvent event)
{
if (logger.isDebugEnabled()) logger.debug("HTTP session created: " + event.getSession().getId());
}
/**
* Session destroyed listener
*/
public void sessionDestroyed(HttpSessionEvent event)
{
if (logger.isDebugEnabled()) logger.debug("HTTP session destroyed: " + event.getSession().getId());
User user;
if (Application.inPortalServer() == false)
{
user = (User)event.getSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
}
else
{
user = (User)event.getSession().getAttribute(AlfrescoFacesPortlet.MANAGED_BEAN_PREFIX + AuthenticationHelper.AUTHENTICATION_USER);
}
if (user != null)
{
// invalidate ticket
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
AuthenticationService authService = (AuthenticationService) ctx.getBean("authenticationService");
authService.invalidateTicket(user.getTicket());
event.getSession().removeAttribute(AuthenticationHelper.AUTHENTICATION_USER);
}
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the GNU Lesser General Public License as
* published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.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.web.app;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Debug phase listener that simply logs when each phase is entered and exited.
*
* @author gavinc
*/
public class DebugPhaseListener implements PhaseListener
{
private static final Log logger = LogFactory.getLog(DebugPhaseListener.class);
/**
* @see javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent)
*/
public void afterPhase(PhaseEvent event)
{
if (logger.isDebugEnabled())
logger.debug("********** Exiting phase: " + event.getPhaseId().toString());
}
/**
* @see javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
*/
public void beforePhase(PhaseEvent event)
{
if (logger.isDebugEnabled())
logger.debug("********** Entering phase: " + event.getPhaseId().toString());
}
/**
* @see javax.faces.event.PhaseListener#getPhaseId()
*/
public PhaseId getPhaseId()
{
return PhaseId.ANY_PHASE;
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.web.app;
import java.util.Enumeration;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import org.apache.log4j.Logger;
import org.apache.log4j.Priority;
/**
* Wrapper around Alfresco Resource Bundle objects. Used to catch and handle missing
* resource exception to help identify missing I18N strings in client apps.
*
* @author Kevin Roast
*/
public final class ResourceBundleWrapper extends ResourceBundle
{
private static Logger logger = Logger.getLogger(ResourceBundleWrapper.class);
private ResourceBundle delegate;
/**
* Constructor
*
* @param bundle The ResourceBundle to route calls too
*/
public ResourceBundleWrapper(ResourceBundle bundle)
{
this.delegate = bundle;
}
/**
* @see java.util.ResourceBundle#getKeys()
*/
public Enumeration<String> getKeys()
{
return this.delegate.getKeys();
}
/**
* @see java.util.ResourceBundle#handleGetObject(java.lang.String)
*/
protected Object handleGetObject(String key)
{
try
{
return this.delegate.getObject(key);
}
catch (MissingResourceException err)
{
if (logger.isEnabledFor(Priority.WARN))
logger.warn("Failed to find I18N message string key: " + key);
return "$$" + key + "$$";
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.web.app.context;
/**
* Interface used to allow Beans to register themselves as interested in UI context events.
* <p>
* Beans supporting this interface should be register against the UIContextService. Then Beans
* which wish to indicate that the UI should refresh itself i.e. dump all cached data and settings,
* call the UIContextService.notifyBeans() to inform all registered instances of the change.
*
* @author Kevin Roast
*/
public interface IContextListener
{
/**
* Method called by UIContextService.notifyBeans() to inform all registered beans that
* all UI Beans should refresh dump all cached data and settings.
*/
public void contextUpdated();
}

View File

@@ -0,0 +1,106 @@
/*
* 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.web.app.context;
import java.util.HashMap;
import java.util.Map;
import javax.faces.context.FacesContext;
/**
* Beans supporting the IContextListener interface are registered against this class. Then Beans
* which wish to indicate that the UI should refresh itself i.e. dump all cached data and settings,
* call the UIContextService.notifyBeans() to inform all registered instances of the change.
*
* @author Kevin Roast
*/
public final class UIContextService
{
/**
* Private constructor
*/
private UIContextService()
{
}
/**
* Returns a Session local instance of the UIContextService
*
* @return UIContextService for this Thread
*/
public static UIContextService getInstance(FacesContext fc)
{
Map session = fc.getExternalContext().getSessionMap();
UIContextService service = (UIContextService)session.get(CONTEXT_KEY);
if (service == null)
{
service = new UIContextService();
session.put(CONTEXT_KEY, service);
}
return service;
}
/**
* Register a bean to be informed of context events
*
* @param bean Conforming to the IContextListener interface
*/
public void registerBean(IContextListener bean)
{
if (bean == null)
{
throw new IllegalArgumentException("Bean reference specified cannot be null!");
}
this.registeredBeans.put(bean.getClass(), bean);
}
/**
* Remove a bean reference from those notified of changes
*
* @param bean Conforming to the IContextListener interface
*/
public void unregisterBean(IContextListener bean)
{
if (bean == null)
{
throw new IllegalArgumentException("Bean reference specified cannot be null!");
}
this.registeredBeans.remove(bean);
}
/**
* Call to notify all register beans that the UI context has changed and they should
* refresh themselves as appropriate.
*/
public void notifyBeans()
{
for (IContextListener listener: this.registeredBeans.values())
{
listener.contextUpdated();
}
}
/** key for the UI context service in the session */
private final static String CONTEXT_KEY = "__uiContextService";
/** Map of bean registered against the context service */
private Map<Class, IContextListener> registeredBeans = new HashMap<Class, IContextListener>(7, 1.0f);
}

View File

@@ -0,0 +1,343 @@
/*
* 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.web.app.portlet;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.util.TempFileProvider;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.AuthenticationHelper;
import org.alfresco.web.bean.ErrorBean;
import org.alfresco.web.bean.FileUploadBean;
import org.alfresco.web.bean.repository.User;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.portlet.PortletFileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.portlet.MyFacesGenericPortlet;
import org.apache.myfaces.portlet.PortletUtil;
import org.springframework.web.context.WebApplicationContext;
/**
* Class to extend the MyFacesGenericPortlet to provide behaviour specific to Alfresco web client.
* Handles upload of multi-part forms through a JSR-168 Portlet, generic error handling and session
* login authentication.
*
* @author Gavin Cornwell, Kevin Roast
*/
public class AlfrescoFacesPortlet extends MyFacesGenericPortlet
{
public static final String INSTANCE_NAME = "AlfrescoClientInstance";
public static final String WINDOW_NAME = "AlfrescoClientWindow";
public static final String MANAGED_BEAN_PREFIX = "javax.portlet.p." + INSTANCE_NAME +
"." + WINDOW_NAME + "?";
private static final String ERROR_PAGE_PARAM = "error-page";
private static final String ERROR_OCCURRED = "error-occurred";
private static Log logger = LogFactory.getLog(AlfrescoFacesPortlet.class);
private String loginPage = null;
private String errorPage = null;
/**
* Called by the portlet container to allow the portlet to process an action request.
*/
public void processAction(ActionRequest request, ActionResponse response)
throws PortletException, IOException
{
boolean isMultipart = PortletFileUpload.isMultipartContent(request);
try
{
// NOTE: Due to filters not being called within portlets we can not make use
// of the MyFaces file upload support, therefore we are using a pure
// portlet request/action to handle file uploads until there is a
// solution.
if (isMultipart)
{
if (logger.isDebugEnabled())
logger.debug("Handling multipart request...");
PortletSession session = request.getPortletSession();
// get the file from the request and put it in the session
DiskFileItemFactory factory = new DiskFileItemFactory();
PortletFileUpload upload = new PortletFileUpload(factory);
List<FileItem> fileItems = upload.parseRequest(request);
Iterator<FileItem> iter = fileItems.iterator();
FileUploadBean bean = new FileUploadBean();
while(iter.hasNext())
{
FileItem item = iter.next();
String filename = item.getName();
if(item.isFormField() == false)
{
if (logger.isDebugEnabled())
logger.debug("Processing uploaded file: " + filename);
// workaround a bug in IE where the full path is returned
// IE is only available for Windows so only check for the Windows path separator
int idx = filename.lastIndexOf('\\');
if (idx == -1)
{
// if there is no windows path separator check for *nix
idx = filename.lastIndexOf('/');
}
if (idx != -1)
{
filename = filename.substring(idx + File.separator.length());
}
File tempFile = TempFileProvider.createTempFile("alfresco", ".upload");
item.write(tempFile);
bean.setFile(tempFile);
bean.setFileName(filename);
bean.setFilePath(tempFile.getAbsolutePath());
session.setAttribute(FileUploadBean.FILE_UPLOAD_BEAN_NAME, bean,
PortletSession.PORTLET_SCOPE);
}
}
// it doesn't matter what the value is we just need the VIEW_ID parameter
// to tell the faces portlet bridge to treat the request as a JSF request,
// this will send us back to the same page we came from, which is fine for
// most scenarios.
response.setRenderParameter(VIEW_ID, "a-jsf-page");
}
else
{
// do the normal JSF processing
super.processAction(request, response);
}
}
catch (Throwable e)
{
if (getErrorPage() != null)
{
handleError(request, response, e);
}
else
{
logger.warn("No error page configured, re-throwing exception");
if (e instanceof PortletException)
{
throw (PortletException)e;
}
else if (e instanceof IOException)
{
throw (IOException)e;
}
else
{
throw new PortletException(e);
}
}
}
}
/**
* @see org.apache.myfaces.portlet.MyFacesGenericPortlet#facesRender(javax.portlet.RenderRequest, javax.portlet.RenderResponse)
*/
protected void facesRender(RenderRequest request, RenderResponse response)
throws PortletException, IOException
{
Application.setInPortalServer(true);
if (request.getParameter(ERROR_OCCURRED) != null)
{
String errorPage = Application.getErrorPage(getPortletContext());
if (logger.isDebugEnabled())
logger.debug("An error has occurred, redirecting to error page: " + errorPage);
response.setContentType("text/html");
PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher(errorPage);
dispatcher.include(request, response);
}
else
{
// if we have no User object in the session then a timeout must have occured
// use the viewId to check that we are not already on the login page
String viewId = request.getParameter(VIEW_ID);
User user = (User)request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
if (user == null && (viewId == null || viewId.equals(getLoginPage()) == false))
{
if (logger.isDebugEnabled())
logger.debug("No valid login, requesting login page. ViewId: " + viewId);
// login page redirect
response.setContentType("text/html");
request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true");
nonFacesRequest(request, response);
}
else
{
try
{
if (user != null)
{
// setup the authentication context
WebApplicationContext ctx = (WebApplicationContext)getPortletContext().getAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
AuthenticationService auth = (AuthenticationService)ctx.getBean("authenticationService");
auth.validate(user.getTicket());
}
// Set the current locale
I18NUtil.setLocale(Application.getLanguage(request.getPortletSession()));
// do the normal JSF processing
super.facesRender(request, response);
}
catch (Throwable e)
{
if (getErrorPage() != null)
{
handleError(request, response, e);
}
else
{
logger.warn("No error page configured, re-throwing exception");
if (e instanceof PortletException)
{
throw (PortletException)e;
}
else if (e instanceof IOException)
{
throw (IOException)e;
}
else
{
throw new PortletException(e);
}
}
}
}
}
}
/**
* Handles errors that occur during a process action request
*/
private void handleError(ActionRequest request, ActionResponse response, Throwable error)
throws PortletException, IOException
{
// get the error bean from the session and set the error that occurred.
PortletSession session = request.getPortletSession();
ErrorBean errorBean = (ErrorBean)session.getAttribute(ErrorBean.ERROR_BEAN_NAME,
PortletSession.PORTLET_SCOPE);
if (errorBean == null)
{
errorBean = new ErrorBean();
session.setAttribute(ErrorBean.ERROR_BEAN_NAME, errorBean, PortletSession.PORTLET_SCOPE);
}
errorBean.setLastError(error);
response.setRenderParameter(ERROR_OCCURRED, "true");
}
/**
* Handles errors that occur during a render request
*/
private void handleError(RenderRequest request, RenderResponse response, Throwable error)
throws PortletException, IOException
{
// get the error bean from the session and set the error that occurred.
PortletSession session = request.getPortletSession();
ErrorBean errorBean = (ErrorBean)session.getAttribute(ErrorBean.ERROR_BEAN_NAME,
PortletSession.PORTLET_SCOPE);
if (errorBean == null)
{
errorBean = new ErrorBean();
session.setAttribute(ErrorBean.ERROR_BEAN_NAME, errorBean, PortletSession.PORTLET_SCOPE);
}
errorBean.setLastError(error);
// if the faces context is available set the current view to the browse page
// so that the error page goes back to the application (rather than going back
// to the same page which just throws the error again meaning we can never leave
// the error page)
FacesContext context = FacesContext.getCurrentInstance();
if (context != null)
{
ViewHandler viewHandler = context.getApplication().getViewHandler();
// TODO: configure the portlet error return page
UIViewRoot view = viewHandler.createView(context, "/jsp/browse/browse.jsp");
context.setViewRoot(view);
}
// get the error page and include that instead
String errorPage = getErrorPage();
if (logger.isDebugEnabled())
logger.debug("An error has occurred, redirecting to error page: " + errorPage);
response.setContentType("text/html");
PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher(errorPage);
dispatcher.include(request, response);
}
/**
* @return Retrieves the configured login page
*/
private String getLoginPage()
{
if (this.loginPage == null)
{
this.loginPage = Application.getLoginPage(getPortletContext());
}
return this.loginPage;
}
/**
* @return Retrieves the configured error page
*/
private String getErrorPage()
{
if (this.errorPage == null)
{
this.errorPage = Application.getErrorPage(getPortletContext());
}
return this.errorPage;
}
}

View File

@@ -0,0 +1,59 @@
/*
* 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.web.app.servlet;
import java.io.IOException;
import javax.faces.webapp.FacesServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.web.app.Application;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Wrapper around standard faces servlet to provide error handling
*
* @author gavinc
*/
public class AlfrescoFacesServlet extends FacesServlet
{
private static Log logger = LogFactory.getLog(AlfrescoFacesServlet.class);
/**
* @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
*/
public void service(ServletRequest request, ServletResponse response)
throws IOException, ServletException
{
try
{
super.service(request, response);
}
catch (Throwable error)
{
String returnPage = ((HttpServletRequest)request).getRequestURI();
Application.handleServletError(getServletConfig().getServletContext(), (HttpServletRequest)request,
(HttpServletResponse)response, error, logger, returnPage);
}
}
}

View File

@@ -0,0 +1,110 @@
/*
* 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.web.app.servlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.LoginBean;
/**
* @author Kevin Roast
*
* Servlet filter responsible for redirecting to the login page for the Web Client if the user
* does not have a valid ticket.
* <p>
* The current ticker is validated for each page request and the login page is shown if the
* ticker has expired.
* <p>
* Note that this filter is only active when the system is running in a servlet container -
* the AlfrescoFacesPortlet will be used for a JSR-168 Portal environment.
*/
public class AuthenticationFilter implements Filter
{
/**
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
public void init(FilterConfig config) throws ServletException
{
this.context = config.getServletContext();
}
/**
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest httpReq = (HttpServletRequest)req;
// allow the login page to proceed
if (httpReq.getRequestURI().endsWith(getLoginPage()) == false)
{
if (AuthenticationHelper.authenticate(this.context, httpReq, (HttpServletResponse)res))
{
// continue filter chaining
chain.doFilter(req, res);
}
else
{
// failed to authenticate - save redirect URL for after login process
httpReq.getSession().setAttribute(LoginBean.LOGIN_REDIRECT_KEY, httpReq.getRequestURI());
}
}
else
{
// continue filter chaining
chain.doFilter(req, res);
}
}
/**
* @see javax.servlet.Filter#destroy()
*/
public void destroy()
{
// nothing to do
}
/**
* @return The login page url
*/
private String getLoginPage()
{
if (this.loginPage == null)
{
this.loginPage = Application.getLoginPage(this.context);
}
return this.loginPage;
}
private String loginPage = null;
private ServletContext context;
}

View File

@@ -0,0 +1,96 @@
/*
* 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.web.app.servlet;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.portlet.AlfrescoFacesPortlet;
import org.alfresco.web.bean.repository.User;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* @author Kevin Roast
*/
public final class AuthenticationHelper
{
public final static String AUTHENTICATION_USER = "_alfAuthTicket";
public static boolean authenticate(ServletContext context, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
throws IOException
{
// examine the appropriate session for our User object
User user;
if (Application.inPortalServer() == false)
{
user = (User)httpRequest.getSession().getAttribute(AUTHENTICATION_USER);
}
else
{
user = (User)httpRequest.getSession().getAttribute(AlfrescoFacesPortlet.MANAGED_BEAN_PREFIX + AUTHENTICATION_USER);
}
if (user == null)
{
// no user/ticket - redirect to login page
httpResponse.sendRedirect(httpRequest.getContextPath() + "/faces" + Application.getLoginPage(context));
return false;
}
else
{
// setup the authentication context
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
AuthenticationService auth = (AuthenticationService)ctx.getBean("authenticationService");
auth.validate(user.getTicket());
// Set the current locale
I18NUtil.setLocale(Application.getLanguage(httpRequest.getSession()));
return true;
}
}
public static boolean authenticate(ServletContext context, HttpServletRequest httpRequest, HttpServletResponse httpResponse, String ticket)
throws IOException
{
// setup the authentication context
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
AuthenticationService auth = (AuthenticationService)ctx.getBean("authenticationService");
try
{
auth.validate(ticket);
}
catch (AuthenticationException authErr)
{
return false;
}
// Set the current locale
I18NUtil.setLocale(Application.getLanguage(httpRequest.getSession()));
return true;
}
}

View File

@@ -0,0 +1,297 @@
/*
* 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.web.app.servlet;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.LoginBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* Servlet responsible for streaming node content from the repo directly to the response stream.
* The appropriate mimetype is calculated based on filename extension.
* <p>
* The URL to the servlet should be generated thus:
* <pre>/alfresco/download/attach/workspace/SpacesStore/0000-0000-0000-0000/myfile.pdf</pre>
* or
* <pre>/alfresco/download/direct/workspace/SpacesStore/0000-0000-0000-0000/myfile.pdf</pre>
* <p>
* The store protocol, followed by the store ID, followed by the content Node Id
* the last element is used for mimetype calculation and browser default filename.
* <p>
* The 'attach' or 'direct' element is used to indicate whether to display the stream directly
* in the browser or download it as a file attachment.
* <p>
* By default, the download assumes that the content is on the
* {@link org.alfresco.model.ContentModel#PROP_CONTENT content property}.<br>
* To retrieve the content of a specific model property, use a 'property' arg, providing the workspace,
* node ID AND the qualified name of the property.
* <p>
* The URL may be followed by a valid ticket argument for authentication: ?ticket=1234567890
*
* @author Kevin Roast
*/
public class DownloadContentServlet extends HttpServlet
{
private static final long serialVersionUID = -4558907921887235966L;
private static Log logger = LogFactory.getLog(DownloadContentServlet.class);
private static final String DOWNLOAD_URL = "/download/attach/{0}/{1}/{2}/{3}";
private static final String BROWSER_URL = "/download/direct/{0}/{1}/{2}/{3}";
private static final String MIMETYPE_OCTET_STREAM = "application/octet-stream";
private static final String MSG_ERROR_CONTENT_MISSING = "error_content_missing";
private static final String ARG_PROPERTY = "property";
private static final String ARG_ATTACH = "attach";
private static final String ARG_TICKET = "ticket";
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
ServletOutputStream out = res.getOutputStream();
try
{
// The URL contains multiple parts
// /alfresco/download/attach/workspace/SpacesStore/0000-0000-0000-0000/myfile.pdf
// the protocol, followed by the store, followed by the Id
// the last part is only used for mimetype and browser use
// may be followed by valid ticket for pre-authenticated usage: ?ticket=1234567890
String uri = req.getRequestURI();
if (logger.isDebugEnabled())
logger.debug("Processing URL: " + uri + (req.getQueryString() != null ? ("?" + req.getQueryString()) : ""));
// see if a ticket has been supplied
String ticket = req.getParameter(ARG_TICKET);
if (ticket == null || ticket.length() == 0)
{
if (AuthenticationHelper.authenticate(getServletContext(), req, res) == false)
{
// authentication failed - no point returning the content as we haven't logged in yet
// so end servlet execution and save the URL so the login page knows what to do later
req.getSession().setAttribute(LoginBean.LOGIN_REDIRECT_KEY, uri);
return;
}
}
else
{
AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
}
// TODO: add compression here?
// see http://servlets.com/jservlet2/examples/ch06/ViewResourceCompress.java for example
// only really needed if we don't use the built in compression of the servlet container
StringTokenizer t = new StringTokenizer(uri, "/");
if (t.countTokens() < 7)
{
throw new IllegalArgumentException("Download URL did not contain all required args: " + uri);
}
t.nextToken(); // skip web app name
t.nextToken(); // skip servlet name
String attachToken = t.nextToken();
boolean attachment = attachToken.equals(ARG_ATTACH);
StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
String id = t.nextToken();
String filename = t.nextToken();
// get property qualified name
QName propertyQName = null;
String property = req.getParameter(ARG_PROPERTY);
if (property == null || property.length() == 0)
{
propertyQName = ContentModel.PROP_CONTENT;
}
else
{
propertyQName = QName.createQName(property);
}
NodeRef nodeRef = new NodeRef(storeRef, id);
if (logger.isDebugEnabled())
{
logger.debug("Found NodeRef: " + nodeRef.toString());
logger.debug("Will use filename: " + filename);
logger.debug("For property: " + propertyQName);
logger.debug("With attachment mode: " + attachment);
}
if (attachment == true)
{
// set header based on filename - will force a Save As from the browse if it doesn't recognise it
// this is better than the default response of the browse trying to display the contents!
// TODO: make this configurable - and check it does not prevent streaming of large files
res.setHeader("Content-Disposition", "attachment;filename=\"" + URLDecoder.decode(filename, "UTF-8") + '"');
}
// get the services we need to retrieve the content
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
ServiceRegistry serviceRegistry = (ServiceRegistry)context.getBean(ServiceRegistry.SERVICE_REGISTRY);
ContentService contentService = serviceRegistry.getContentService();
// get the content reader
ContentReader reader = contentService.getReader(nodeRef, propertyQName);
// ensure that it is safe to use
reader = FileContentReader.getSafeContentReader(
reader,
Application.getMessage(req.getSession(), MSG_ERROR_CONTENT_MISSING),
nodeRef, reader);
String mimetype = reader.getMimetype();
// fall back if unable to resolve mimetype property
if (mimetype == null || mimetype.length() == 0)
{
MimetypeService mimetypeMap = serviceRegistry.getMimetypeService();
mimetype = MIMETYPE_OCTET_STREAM;
int extIndex = filename.lastIndexOf('.');
if (extIndex != -1)
{
String ext = filename.substring(extIndex + 1);
String mt = mimetypeMap.getMimetypesByExtension().get(ext);
if (mt != null)
{
mimetype = mt;
}
}
}
res.setContentType(mimetype);
// get the content and stream directly to the response output stream
// assuming the repo is capable of streaming in chunks, this should allow large files
// to be streamed directly to the browser response stream.
try
{
reader.getContent( res.getOutputStream() );
}
catch (SocketException e)
{
if (e.getMessage().contains("ClientAbortException"))
{
// the client cut the connection - our mission was accomplished apart from a little error message
logger.error("Client aborted stream read:\n node: " + nodeRef + "\n content: " + reader);
}
else
{
throw e;
}
}
}
catch (Throwable err)
{
throw new AlfrescoRuntimeException("Error during download content servlet processing: " + err.getMessage(), err);
}
finally
{
out.close();
}
}
/**
* Helper to generate a URL to a content node for downloading content from the server.
* The content is supplied as an HTTP1.1 attachment to the response. This generally means
* a browser should prompt the user to save the content to specified location.
*
* @param ref NodeRef of the content node to generate URL for (cannot be null)
* @param name File name to return in the URL (cannot be null)
*
* @return URL to download the content from the specified node
*/
public final static String generateDownloadURL(NodeRef ref, String name)
{
String url = null;
try
{
url = MessageFormat.format(DOWNLOAD_URL, new Object[] {
ref.getStoreRef().getProtocol(),
ref.getStoreRef().getIdentifier(),
ref.getId(),
URLEncoder.encode(name, "US-ASCII") } );
}
catch (UnsupportedEncodingException uee)
{
throw new AlfrescoRuntimeException("Failed to encode content URL for node: " + ref, uee);
}
return url;
}
/**
* Helper to generate a URL to a content node for downloading content from the server.
* The content is supplied directly in the reponse. This generally means a browser will
* attempt to open the content directly if possible, else it will prompt to save the file.
*
* @param ref NodeRef of the content node to generate URL for (cannot be null)
* @param name File name to return in the URL (cannot be null)
*
* @return URL to download the content from the specified node
*/
public final static String generateBrowserURL(NodeRef ref, String name)
{
String url = null;
try
{
url = MessageFormat.format(BROWSER_URL, new Object[] {
ref.getStoreRef().getProtocol(),
ref.getStoreRef().getIdentifier(),
ref.getId(),
URLEncoder.encode(name, "US-ASCII") } );
}
catch (UnsupportedEncodingException uee)
{
throw new AlfrescoRuntimeException("Failed to encode content URL for node: " + ref, uee);
}
return url;
}
}

View File

@@ -0,0 +1,130 @@
/*
* 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.web.app.servlet;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.web.bean.LoginBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Servlet allowing external URL access to various global JSF views in the Web Client.
* <p>
* The servlet accepts a well formed URL that can easily be generated from a Content or Space NodeRef.
* The URL also specifies the JSF "outcome" to be executed which provides the correct JSF View to be
* displayed. The JSF "outcome" must equate to a global navigation rule or it will not be displayed.
* Servlet URL is of the form:
* <p>
* <code>http://&lt;server&gt;/alfresco/navigate/&lt;outcome&gt;[/&lt;workspace&gt;/&lt;store&gt;/&lt;nodeId&gt;]</code> or <br/>
* <code>http://&lt;server&gt;/alfresco/navigate/&lt;outcome&gt;[/webdav/&lt;path/to/node&gt;]</code>
* </p>
*
* @author Kevin Roast
*/
public class ExternalAccessServlet extends HttpServlet
{
private static final long serialVersionUID = -4118907921337237802L;
private static Log logger = LogFactory.getLog(ExternalAccessServlet.class);
/**
* @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
boolean alreadyAuthenticated = AuthenticationHelper.authenticate(getServletContext(), req, res);
// The URL contains multiple parts
// /alfresco/navigate/<outcome>
String uri = req.getRequestURI();
if (logger.isDebugEnabled())
logger.debug("Processing URL: " + uri);
StringTokenizer t = new StringTokenizer(uri, "/");
int count = t.countTokens();
if (count < 3)
{
throw new IllegalArgumentException("Externally addressable URL did not contain all required args: " + uri);
}
t.nextToken(); // skip web app name
t.nextToken(); // skip servlet name
String outcome = t.nextToken();
// get rest of the tokens
String[] tokens = new String[count - 3];
for (int i=0; i<count - 3; i++)
{
tokens[i] = t.nextToken();
}
// set the session variable so the login bean knows which outcome to use
req.getSession().setAttribute(LoginBean.LOGIN_OUTCOME_KEY, outcome);
// set the args if any
req.getSession().setAttribute(LoginBean.LOGIN_OUTCOME_ARGS, tokens);
if (alreadyAuthenticated)
{
// clear the User object from the Session - this will force a relogin
// we do this so the outcome from the login page can then be changed
req.getSession().removeAttribute(AuthenticationHelper.AUTHENTICATION_USER);
if (logger.isDebugEnabled())
logger.debug("Removing User session - will redirect via login page...");
// redirect to root URL will force the login page to appear via the Authentication Filter
res.sendRedirect(req.getContextPath());
}
}
/**
* Generate a URL to the External Access Servlet.
* Allows access to JSF views (via an "outcome" ID) from external URLs.
*
* @param outcome
* @param args
*
* @return URL
*/
public final static String generateExternalURL(String outcome, String args)
{
if (args == null)
{
return MessageFormat.format(EXTERNAL_URL, new Object[] {outcome} );
}
else
{
return MessageFormat.format(EXTERNAL_URL_ARGS, new Object[] {outcome, args} );
}
}
// example: http://<server>/alfresco/navigate/<outcome>[/<workspace>/<store>/<nodeId>]
private static final String EXTERNAL_URL = "/navigate/{0}";
private static final String EXTERNAL_URL_ARGS = "/navigate/{0}/{1}";
}

View File

@@ -0,0 +1,69 @@
/*
* 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.web.app.servlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.alfresco.web.app.Application;
/**
* Filter that determines whether the application is running inside a portal
* server or servlet engine. The fact that this filter gets called means
* the application is running inside a servlet engine.
*
* @author gavinc
*/
public class ModeDetectionFilter implements Filter
{
/**
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
public void init(FilterConfig config) throws ServletException
{
// nothing to do
}
/**
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException
{
// as we get here means we are inside a servlet engine as portal servers
// do not support the calling of filters yet
Application.setInPortalServer(false);
// continue filter chaining
chain.doFilter(req, res);
}
/**
* @see javax.servlet.Filter#destroy()
*/
public void destroy()
{
// nothing to do
}
}

View File

@@ -0,0 +1,274 @@
/*
* 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.web.app.servlet;
import java.io.IOException;
import java.net.SocketException;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.template.DateCompareMethod;
import org.alfresco.repo.template.HasAspectMethod;
import org.alfresco.repo.template.I18NMessageMethod;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.TemplateException;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.LoginBean;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.ui.common.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* Servlet responsible for streaming content from a template processed against a node directly
* to the response stream.
* <p>
* The URL to the servlet should be generated thus:
* <pre>/alfresco/template/workspace/SpacesStore/0000-0000-0000-0000
* or
* <pre>/alfresco/template/workspace/SpacesStore/0000-0000-0000-0000/workspace/SpacesStore/0000-0000-0000-0000
* <p>
* The store protocol, followed by the store ID, followed by the content Node Id used to
* identify the node to execute the default template for. The second set of elements encode
* the store and node Id of the template to used if a default is not set or not requested.
* <p>
* The URL may be followed by a valid 'ticket' argument for authentication: ?ticket=1234567890
* <br>
* And may be followed by a 'mimetype' argument specifying the mimetype to return the result as
* on the stream. Otherwise it is assumed that HTML is the default response mimetype.
*
* @author Kevin Roast
*/
public class TemplateContentServlet extends HttpServlet
{
private static final String MIMETYPE_HTML = "text/html";
private static final long serialVersionUID = -4123407921997235977L;
private static Log logger = LogFactory.getLog(TemplateContentServlet.class);
private static final String DEFAULT_URL = "/template/{0}/{1}/{2}";
private static final String TEMPALTE_URL = "/template/{0}/{1}/{2}/{3}/{4}/{5}";
private static final String MSG_ERROR_CONTENT_MISSING = "error_content_missing";
private static final String ARG_TICKET = "ticket";
private static final String ARG_MIMETYPE = "mimetype";
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
try
{
String uri = req.getRequestURI();
if (logger.isDebugEnabled())
logger.debug("Processing URL: " + uri + (req.getQueryString() != null ? ("?" + req.getQueryString()) : ""));
// see if a ticket has been supplied
String ticket = req.getParameter(ARG_TICKET);
if (ticket == null || ticket.length() == 0)
{
if (AuthenticationHelper.authenticate(getServletContext(), req, res) == false)
{
// authentication failed - no point returning the content as we haven't logged in yet
// so end servlet execution and save the URL so the login page knows what to do later
req.getSession().setAttribute(LoginBean.LOGIN_REDIRECT_KEY, uri);
return;
}
}
else
{
AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
}
StringTokenizer t = new StringTokenizer(uri, "/");
int tokenCount = t.countTokens();
if (tokenCount < 5)
{
throw new IllegalArgumentException("Download URL did not contain all required args: " + uri);
}
t.nextToken(); // skip web app name
t.nextToken(); // skip servlet name
// get NodeRef to the content
StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
NodeRef nodeRef = new NodeRef(storeRef, t.nextToken());
// get NodeRef to the template if supplied
NodeRef templateRef = null;
if (tokenCount == 8)
{
storeRef = new StoreRef(t.nextToken(), t.nextToken());
templateRef = new NodeRef(storeRef, t.nextToken());
}
// get the services we need to retrieve the content
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
ServiceRegistry serviceRegistry = (ServiceRegistry)context.getBean(ServiceRegistry.SERVICE_REGISTRY);
NodeService nodeService = serviceRegistry.getNodeService();
TemplateService templateService = serviceRegistry.getTemplateService();
UserTransaction txn = null;
try
{
txn = serviceRegistry.getTransactionService().getUserTransaction(true);
txn.begin();
// if template not supplied, then use the default against the node
if (templateRef == null)
{
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPLATABLE))
{
templateRef = (NodeRef)nodeService.getProperty(nodeRef, ContentModel.PROP_TEMPLATE);
}
if (templateRef == null)
{
throw new TemplateException("Template reference not set against node or not supplied in URL.");
}
}
// create the model - put the supplied noderef in as space/document as appropriate
Object model = getModel(serviceRegistry, req.getSession(), nodeRef);
// process the template against the node content directly to the response output stream
// assuming the repo is capable of streaming in chunks, this should allow large files
// to be streamed directly to the browser response stream.
try
{
templateService.processTemplate(
null,
templateRef.toString(),
model,
res.getWriter());
// commit the transaction
txn.commit();
}
catch (SocketException e)
{
if (e.getMessage().contains("ClientAbortException"))
{
// the client cut the connection - our mission was accomplished apart from a little error message
logger.error("Client aborted stream read:\n node: " + nodeRef + "\n template: " + templateRef);
try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
}
else
{
throw e;
}
}
}
catch (Throwable txnErr)
{
try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
}
}
catch (Throwable err)
{
throw new AlfrescoRuntimeException("Error during download content servlet processing: " + err.getMessage(), err);
}
}
private Object getModel(ServiceRegistry services, HttpSession session, NodeRef nodeRef)
{
// create FreeMarker default model and merge
Map root = new HashMap(11, 1.0f);
// supply the CompanyHome space as "companyhome"
NodeRef companyRootRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
TemplateNode companyRootNode = new TemplateNode(companyRootRef, services, imageResolver);
root.put("companyhome", companyRootNode);
// supply the users Home Space as "userhome"
User user = Application.getCurrentUser(session);
NodeRef userRootRef = new NodeRef(Repository.getStoreRef(), user.getHomeSpaceId());
TemplateNode userRootNode = new TemplateNode(userRootRef, services, imageResolver);
root.put("userhome", userRootNode);
// put the current NodeRef in as "space" and "document"
TemplateNode node = new TemplateNode(nodeRef, services, imageResolver);
root.put("space", node);
root.put("document", node);
// supply the current user Node as "person"
root.put("person", new TemplateNode(user.getPerson(), services, imageResolver));
// current date/time is useful to have and isn't supplied by FreeMarker by default
root.put("date", new Date());
// add custom method objects
root.put("hasAspect", new HasAspectMethod());
root.put("message", new I18NMessageMethod());
root.put("dateCompare", new DateCompareMethod());
return root;
}
/** Template Image resolver helper */
private TemplateImageResolver imageResolver = new TemplateImageResolver()
{
public String resolveImagePathForName(String filename, boolean small)
{
return Utils.getFileTypeImage(filename, small);
}
};
/**
* Helper to generate a URL to a content node for downloading content from the server.
* The content is supplied as an HTTP1.1 attachment to the response. This generally means
* a browser should prompt the user to save the content to specified location.
*
* @param ref NodeRef of the content node to generate URL for (cannot be null)
* @param name File name to return in the URL (cannot be null)
*
* @return URL to download the content from the specified node
*/
public final static String generateURL(NodeRef ref, String name)
{
return MessageFormat.format(DEFAULT_URL, new Object[] {
ref.getStoreRef().getProtocol(),
ref.getStoreRef().getIdentifier(),
ref.getId() } );
}
}

View File

@@ -0,0 +1,141 @@
/*
* 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.web.app.servlet;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.util.TempFileProvider;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.FileUploadBean;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Servlet that takes a file uploaded via a browser and represents it as an
* UploadFileBean in the session
*
* @author gavinc
*/
public class UploadFileServlet extends HttpServlet
{
private static final long serialVersionUID = -5482538466491052873L;
private static Log logger = LogFactory.getLog(UploadFileServlet.class);
/**
* @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String returnPage = null;
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
try
{
AuthenticationHelper.authenticate(getServletContext(), request, response);
if (isMultipart == false)
{
throw new AlfrescoRuntimeException("This servlet can only be used to handle file upload requests, make" +
"sure you have set the enctype attribute on your form to multipart/form-data");
}
if (logger.isDebugEnabled())
logger.debug("Uploading servlet servicing...");
HttpSession session = request.getSession();
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
List<FileItem> fileItems = upload.parseRequest(request);
Iterator<FileItem> iter = fileItems.iterator();
FileUploadBean bean = new FileUploadBean();
while(iter.hasNext())
{
FileItem item = iter.next();
if(item.isFormField())
{
if (item.getFieldName().equalsIgnoreCase("return-page"))
{
returnPage = item.getString();
}
}
else
{
String filename = item.getName();
if (filename != null && filename.length() != 0)
{
if (logger.isDebugEnabled())
logger.debug("Processing uploaded file: " + filename);
// workaround a bug in IE where the full path is returned
// IE is only available for Windows so only check for the Windows path separator
int idx = filename.lastIndexOf('\\');
if (idx == -1)
{
// if there is no windows path separator check for *nix
idx = filename.lastIndexOf('/');
}
if (idx != -1)
{
filename = filename.substring(idx + File.separator.length());
}
File tempFile = TempFileProvider.createTempFile("alfresco", ".upload");
item.write(tempFile);
bean.setFile(tempFile);
bean.setFileName(filename);
bean.setFilePath(tempFile.getAbsolutePath());
session.setAttribute(FileUploadBean.FILE_UPLOAD_BEAN_NAME, bean);
if (logger.isDebugEnabled())
logger.debug("Temp file: " + tempFile.getAbsolutePath() + " created from upload filename: " + filename);
}
}
}
if (returnPage == null || returnPage.length() == 0)
{
throw new AlfrescoRuntimeException("return-page parameter has not been supplied");
}
// finally redirect
if (logger.isDebugEnabled())
logger.debug("Upload servicing complete, redirecting to: " + returnPage);
response.sendRedirect(returnPage);
}
catch (Throwable error)
{
Application.handleServletError(getServletContext(), (HttpServletRequest)request,
(HttpServletResponse)response, error, logger, returnPage);
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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.web.bean;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.alfresco.config.xml.XMLConfigService;
import org.alfresco.web.app.Application;
import org.springframework.web.jsf.FacesContextUtils;
/**
* Bean used for administration purposes
*
* @author gavinc
*/
public class AdminBean
{
/**
* Resets the config service
*
* @param event Event that caused the request for the reset
*/
public void resetConfigService(ActionEvent event)
{
// get the config service
XMLConfigService configSvc = (XMLConfigService)FacesContextUtils.getRequiredWebApplicationContext(
FacesContext.getCurrentInstance()).getBean(Application.BEAN_CONFIG_SERVICE);
// reset it
configSvc.reset();
}
}

View File

@@ -0,0 +1,741 @@
/*
* 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.web.bean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.search.ISO9075;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.AssociationRef;
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.Path;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.web.app.servlet.DownloadContentServlet;
// TODO: DownloadServlet - use of request parameter for property name?
// TODO: Anyway to switch content view url link / property value text?
/**
* Backing bean to support the Admin Node Browser
*/
public class AdminNodeBrowseBean
{
/** selected query language */
private String queryLanguage = null;
/** available query languages */
private static List<SelectItem> queryLanguages = new ArrayList<SelectItem>();
static
{
queryLanguages.add(new SelectItem("noderef"));
queryLanguages.add(new SelectItem(SearchService.LANGUAGE_XPATH));
queryLanguages.add(new SelectItem(SearchService.LANGUAGE_LUCENE));
}
// query and results
private String query = null;
private SearchResults searchResults = new SearchResults(null);
// stores and node
private DataModel stores = null;
private NodeRef nodeRef = null;
private QName nodeType = null;
private Path primaryPath = null;
private DataModel parents = null;
private DataModel aspects = null;
private DataModel properties = null;
private DataModel children = null;
private DataModel assocs = null;
// supporting repository services
private NodeService nodeService;
private DictionaryService dictionaryService;
private SearchService searchService;
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param searchService search service
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @param dictionaryService dictionary service
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* Gets the list of repository stores
*
* @return stores
*/
public DataModel getStores()
{
if (stores == null)
{
List<StoreRef> storeRefs = nodeService.getStores();
stores = new ListDataModel(storeRefs);
}
return stores;
}
/**
* Gets the selected node reference
*
* @return node reference (defaults to system store root)
*/
public NodeRef getNodeRef()
{
if (nodeRef == null)
{
nodeRef = nodeService.getRootNode(new StoreRef("system", "system"));
}
return nodeRef;
}
/**
* Sets the selected node reference
*
* @param nodeRef node reference
*/
private void setNodeRef(NodeRef nodeRef)
{
this.nodeRef = nodeRef;
// clear cache
primaryPath = null;
nodeType = null;
parents = null;
aspects = null;
properties = null;
children = null;
assocs = null;
}
/**
* Gets the current node type
*
* @return node type
*/
public QName getNodeType()
{
if (nodeType == null)
{
nodeType = nodeService.getType(getNodeRef());
}
return nodeType;
}
/**
* Gets the current node primary path
*
* @return primary path
*/
public String getPrimaryPath()
{
if (primaryPath == null)
{
primaryPath = nodeService.getPath(getNodeRef());
}
return ISO9075.decode(primaryPath.toString());
}
/**
* Gets the current node primary parent reference
*
* @return primary parent ref
*/
public NodeRef getPrimaryParent()
{
getPrimaryPath();
Path.Element element = primaryPath.last();
NodeRef parentRef = ((Path.ChildAssocElement)element).getRef().getParentRef();
return parentRef;
}
/**
* Gets the current node aspects
*
* @return node aspects
*/
public DataModel getAspects()
{
if (aspects == null)
{
List<QName> aspectNames = new ArrayList<QName>(nodeService.getAspects(getNodeRef()));
aspects = new ListDataModel(aspectNames);
}
return aspects;
}
/**
* Gets the current node parents
*
* @return node parents
*/
public DataModel getParents()
{
if (parents == null)
{
List<ChildAssociationRef> parentRefs = nodeService.getParentAssocs(getNodeRef());
parents = new ListDataModel(parentRefs);
}
return parents;
}
/**
* Gets the current node properties
*
* @return properties
*/
public DataModel getProperties()
{
if (properties == null)
{
Map<QName, Serializable> propertyValues = nodeService.getProperties(getNodeRef());
List<Property> nodeProperties = new ArrayList<Property>(propertyValues.size());
for (Map.Entry<QName, Serializable> property : propertyValues.entrySet())
{
nodeProperties.add(new Property(property.getKey(), property.getValue()));
}
properties = new ListDataModel(nodeProperties);
}
return properties;
}
/**
* Gets the current node children
*
* @return node children
*/
public DataModel getChildren()
{
if (children == null)
{
List<ChildAssociationRef> assocRefs = nodeService.getChildAssocs(getNodeRef());
children = new ListDataModel(assocRefs);
}
return children;
}
/**
* Gets the current node associations
*
* @return associations
*/
public DataModel getAssocs()
{
if (assocs == null)
{
List<AssociationRef> assocRefs = nodeService.getTargetAssocs(getNodeRef(), RegexQNamePattern.MATCH_ALL);
assocs = new ListDataModel(assocRefs);
}
return assocs;
}
/**
* Gets the current query language
*
* @return query language
*/
public String getQueryLanguage()
{
return queryLanguage;
}
/**
* Sets the current query language
*
* @param queryLanguage query language
*/
public void setQueryLanguage(String queryLanguage)
{
this.queryLanguage = queryLanguage;
}
/**
* Gets the current query
*
* @return query statement
*/
public String getQuery()
{
return query;
}
/**
* Set the current query
*
* @param query query statement
*/
public void setQuery(String query)
{
this.query = query;
}
/**
* Gets the list of available query languages
*
* @return query languages
*/
public List getQueryLanguages()
{
return queryLanguages;
}
/**
* Gets the current search results
*
* @return search results
*/
public SearchResults getSearchResults()
{
return searchResults;
}
/**
* Action to select a store
*
* @return next action
*/
public String selectStore()
{
StoreRef storeRef = (StoreRef)stores.getRowData();
NodeRef rootNode = nodeService.getRootNode(storeRef);
setNodeRef(rootNode);
return "success";
}
/**
* Action to select stores list
*
* @return next action
*/
public String selectStores()
{
stores = null;
return "success";
}
/**
* Action to select primary path
*
* @return next action
*/
public String selectPrimaryPath()
{
// force refresh of self
setNodeRef(nodeRef);
return "success";
}
/**
* Action to select primary parent
*
* @return next action
*/
public String selectPrimaryParent()
{
setNodeRef(getPrimaryParent());
return "success";
}
/**
* Action to select parent
*
* @return next action
*/
public String selectParent()
{
ChildAssociationRef assocRef = (ChildAssociationRef)parents.getRowData();
NodeRef parentRef = assocRef.getParentRef();
setNodeRef(parentRef);
return "success";
}
/**
* Action to select association To node
*
* @return next action
*/
public String selectToNode()
{
AssociationRef assocRef = (AssociationRef)assocs.getRowData();
NodeRef targetRef = assocRef.getTargetRef();
setNodeRef(targetRef);
return "success";
}
/**
* Action to select node property
*
* @return next action
*/
public String selectNodeProperty()
{
Property property = (Property)properties.getRowData();
Property.Value value = (Property.Value)property.getValues().getRowData();
NodeRef nodeRef = (NodeRef)value.getValue();
setNodeRef(nodeRef);
return "success";
}
/**
* Action to select child
*
* @return next action
*/
public String selectChild()
{
ChildAssociationRef assocRef = (ChildAssociationRef)children.getRowData();
NodeRef childRef = assocRef.getChildRef();
setNodeRef(childRef);
return "success";
}
/**
* Action to select search result node
*
* @return next action
*/
public String selectResultNode()
{
ChildAssociationRef assocRef = (ChildAssociationRef)searchResults.getRows().getRowData();
NodeRef childRef = assocRef.getChildRef();
setNodeRef(childRef);
return "success";
}
/**
* Action to submit search
*
* @return next action
*/
public String submitSearch()
{
try
{
if (queryLanguage.equals("noderef"))
{
// ensure node exists
NodeRef nodeRef = new NodeRef(query);
boolean exists = nodeService.exists(nodeRef);
if (!exists)
{
throw new AlfrescoRuntimeException("Node " + nodeRef + " does not exist.");
}
setNodeRef(nodeRef);
return "node";
}
// perform search
searchResults = new SearchResults(searchService.query(getNodeRef().getStoreRef(), queryLanguage, query));
return "search";
}
catch(Throwable e)
{
FacesContext context = FacesContext.getCurrentInstance();
FacesMessage message = new FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_ERROR);
message.setDetail("Search failed due to: " + e.toString());
context.addMessage("searchForm:query", message);
return "error";
}
}
/**
* Property wrapper class
*/
public class Property
{
private QName name;
private boolean isCollection = false;
private DataModel values;
private String datatype;
private String residual;
/**
* Construct
*
* @param name property name
* @param value property values
*/
public Property(QName name, Serializable value)
{
this.name = name;
PropertyDefinition propDef = dictionaryService.getProperty(name);
if (propDef != null)
{
datatype = propDef.getDataType().getName().toString();
residual = "false";
}
else
{
residual = "true";
}
// handle multi/single values
// TODO: perhaps this is not the most efficient way - lots of list creations
List<Value> values = new ArrayList<Value>();
if (value instanceof Collection)
{
isCollection = true;
for (Serializable multiValue : (Collection<Serializable>)value)
{
values.add(new Value(multiValue));
}
}
else
{
values.add(new Value(value));
}
this.values = new ListDataModel(values);
}
/**
* Gets the property name
*
* @return name
*/
public QName getName()
{
return name;
}
/**
* Gets the property data type
*
* @return data type
*/
public String getDataType()
{
return datatype;
}
/**
* Gets the property value
*
* @return value
*/
public DataModel getValues()
{
return values;
}
/**
* Determines whether the property is residual
*
* @return true => property is not defined in dictionary
*/
public String getResidual()
{
return residual;
}
/**
* Determines whether the property is of ANY type
*
* @return true => is any
*/
public boolean isAny()
{
return (datatype == null) ? false : datatype.equals(DataTypeDefinition.ANY.toString());
}
/**
* Determines whether the property is a collection
*
* @return true => is collection
*/
public boolean isCollection()
{
return isCollection;
}
/**
* Value wrapper
*/
public class Value
{
private Serializable value;
/**
* Construct
*
* @param value value
*/
public Value(Serializable value)
{
this.value = value;
}
/**
* Gets the value
*
* @return the value
*/
public Serializable getValue()
{
return value;
}
/**
* Gets the value datatype
*
* @return the value datatype
*/
public String getDataType()
{
String datatype = Property.this.getDataType();
if (datatype == null || datatype.equals(DataTypeDefinition.ANY.toString()))
{
if (value != null)
{
datatype = dictionaryService.getDataType(value.getClass()).getName().toString();
}
}
return datatype;
}
/**
* Gets the download url (for content properties)
*
* @return url
*/
public String getUrl()
{
String url = FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath();
url += DownloadContentServlet.generateBrowserURL(nodeRef, "file.bin");
url += "?property=" + name;
return url;
}
/**
* Determines whether the value is content
*
* @return true => is content
*/
public boolean isContent()
{
String datatype = getDataType();
return (datatype == null) ? false : datatype.equals(DataTypeDefinition.CONTENT.toString());
}
/**
* Determines whether the value is a node ref
*
* @return true => is node ref
*/
public boolean isNodeRef()
{
String datatype = getDataType();
return (datatype == null) ? false : datatype.equals(DataTypeDefinition.NODE_REF.toString()) || datatype.equals(DataTypeDefinition.CATEGORY.toString());
}
/**
* Determines whether the value is null
*
* @return true => value is null
*/
public boolean isNullValue()
{
return value == null;
}
}
}
/**
* Wrapper class for Search Results
*/
public class SearchResults
{
private int length = 0;
private DataModel rows;
/**
* Construct
*
* @param resultSet query result set
*/
public SearchResults(ResultSet resultSet)
{
rows = new ListDataModel();
if (resultSet != null)
{
rows.setWrappedData(resultSet.getChildAssocRefs());
length = resultSet.length();
}
}
/**
* Gets the row count
*
* @return count of rows
*/
public int getLength()
{
return length;
}
/**
* Gets the rows
*
* @return the rows
*/
public DataModel getRows()
{
return rows;
}
}
}

View File

@@ -0,0 +1,829 @@
/*
* 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.web.bean;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import org.alfresco.config.ConfigService;
import org.alfresco.model.ContentModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.CachingDateFormat;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.config.ClientConfigElement;
import org.alfresco.web.config.ClientConfigElement.CustomProperty;
import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
import org.alfresco.web.ui.common.component.UIPanel.ExpandedEvent;
import org.alfresco.web.ui.repo.component.UISearchCustomProperties;
/**
* Provides the form state and action event handling for the Advanced Search UI.
* <p>
* Integrates with the web-client ConfigService to retrieve configuration of custom
* meta-data searching fields. Custom fields can be configured to appear in the UI
* and they are they automatically added to the search query by this bean.
*
* @author Kevin Roast
*/
public class AdvancedSearchBean
{
/**
* Default constructor
*/
public AdvancedSearchBean()
{
// initial state of progressive panels that don't use the default
panels.put("categories-panel", false);
panels.put("attrs-panel", false);
panels.put("custom-panel", false);
}
// ------------------------------------------------------------------------------
// Bean property getters and setters
/**
* @param navigator The NavigationBean to set.
*/
public void setNavigator(NavigationBean navigator)
{
this.navigator = navigator;
}
/**
* @param nodeService The NodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param namespaceService The NamespaceService to set.
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @return Returns the progressive panels expanded state map.
*/
public Map<String, Boolean> getPanels()
{
return this.panels;
}
/**
* @param panels The progressive panels expanded state map.
*/
public void setPanels(Map<String, Boolean> panels)
{
this.panels = panels;
}
/**
* @return Returns the folder to search, null for all.
*/
public String getLookin()
{
return this.lookin;
}
/**
* @param lookin The folder to search in or null for all.
*/
public void setLookin(String lookIn)
{
this.lookin = lookIn;
}
/**
* @return Returns the location.
*/
public NodeRef getLocation()
{
return this.location;
}
/**
* @param location The location to set.
*/
public void setLocation(NodeRef location)
{
this.location = location;
}
/**
* @return Returns the search mode.
*/
public String getMode()
{
return this.mode;
}
/**
* @param mode The search mode to set.
*/
public void setMode(String mode)
{
this.mode = mode;
}
/**
* @return Returns the text to search for.
*/
public String getText()
{
return this.text;
}
/**
* @param text The text to set.
*/
public void setText(String text)
{
this.text = text;
}
/**
* @return Returns the category.
*/
public NodeRef getCategory()
{
return this.category;
}
/**
* @param category The category to set.
*/
public void setCategory(NodeRef category)
{
this.category = category;
}
/**
* @return Returns true to search location children, false for just the specified location.
*/
public boolean getLocationChildren()
{
return this.locationChildren;
}
/**
* @param locationChildren True to search location children, false for just the specified location.
*/
public void setLocationChildren(boolean locationChildren)
{
this.locationChildren = locationChildren;
}
/**
* @return Returns true to search category children, false for just the specified category.
*/
public boolean getCategoryChildren()
{
return this.categoryChildren;
}
/**
* @param categoryChildren True to search category children, false for just the specified category.
*/
public void setCategoryChildren(boolean categoryChildren)
{
this.categoryChildren = categoryChildren;
}
/**
* @return Returns the createdDateFrom.
*/
public Date getCreatedDateFrom()
{
return this.createdDateFrom;
}
/**
* @param createdDateFrom The createdDateFrom to set.
*/
public void setCreatedDateFrom(Date createdDate)
{
this.createdDateFrom = createdDate;
}
/**
* @return Returns the description.
*/
public String getDescription()
{
return this.description;
}
/**
* @param description The description to set.
*/
public void setDescription(String description)
{
this.description = description;
}
/**
* @return Returns the modifiedDateFrom.
*/
public Date getModifiedDateFrom()
{
return this.modifiedDateFrom;
}
/**
* @param modifiedDateFrom The modifiedDateFrom to set.
*/
public void setModifiedDateFrom(Date modifiedDate)
{
this.modifiedDateFrom = modifiedDate;
}
/**
* @return Returns the createdDateTo.
*/
public Date getCreatedDateTo()
{
return this.createdDateTo;
}
/**
* @param createdDateTo The createdDateTo to set.
*/
public void setCreatedDateTo(Date createdDateTo)
{
this.createdDateTo = createdDateTo;
}
/**
* @return Returns the modifiedDateTo.
*/
public Date getModifiedDateTo()
{
return this.modifiedDateTo;
}
/**
* @param modifiedDateTo The modifiedDateTo to set.
*/
public void setModifiedDateTo(Date modifiedDateTo)
{
this.modifiedDateTo = modifiedDateTo;
}
/**
* @return Returns the title.
*/
public String getTitle()
{
return this.title;
}
/**
* @param title The title to set.
*/
public void setTitle(String title)
{
this.title = title;
}
/**
* @return Returns the author.
*/
public String getAuthor()
{
return this.author;
}
/**
* @param author The author to set.
*/
public void setAuthor(String author)
{
this.author = author;
}
/**
* @return Returns the modifiedDateChecked.
*/
public boolean isModifiedDateChecked()
{
return this.modifiedDateChecked;
}
/**
* @param modifiedDateChecked The modifiedDateChecked to set.
*/
public void setModifiedDateChecked(boolean modifiedDateChecked)
{
this.modifiedDateChecked = modifiedDateChecked;
}
/**
* @return Returns the createdDateChecked.
*/
public boolean isCreatedDateChecked()
{
return this.createdDateChecked;
}
/**
* @return Returns the content type currenty selected
*/
public String getContentType()
{
return this.contentType;
}
/**
* @param contentType Sets the currently selected content type
*/
public void setContentType(String contentType)
{
this.contentType = contentType;
}
/**
* @return Returns the contentFormat.
*/
public String getContentFormat()
{
return this.contentFormat;
}
/**
* @param contentFormat The contentFormat to set.
*/
public void setContentFormat(String contentFormat)
{
this.contentFormat = contentFormat;
}
/**
* @return Returns the custom properties Map.
*/
public Map<String, Object> getCustomProperties()
{
return this.customProperties;
}
/**
* @param customProperties The custom properties Map to set.
*/
public void setCustomProperties(Map<String, Object> customProperties)
{
this.customProperties = customProperties;
}
/**
* @param createdDateChecked The createdDateChecked to set.
*/
public void setCreatedDateChecked(boolean createdDateChecked)
{
this.createdDateChecked = createdDateChecked;
}
/**
* @return Returns a list of content object types to allow the user to select from
*/
public List<SelectItem> getContentTypes()
{
if (this.contentTypes == null)
{
FacesContext context = FacesContext.getCurrentInstance();
// add the well known cm:content object type by default
this.contentTypes = new ArrayList<SelectItem>(5);
this.contentTypes.add(new SelectItem(ContentModel.TYPE_CONTENT.toString(),
Application.getMessage(context, MSG_CONTENT)));
// add any configured content sub-types to the list
List<String> types = getClientConfig().getContentTypes();
if (types != null)
{
DictionaryService dictionaryService = Repository.getServiceRegistry(context).getDictionaryService();
for (String type : types)
{
QName idQName = Repository.resolveToQName(type);
TypeDefinition typeDef = dictionaryService.getType(idQName);
if (typeDef != null && dictionaryService.isSubClass(typeDef.getName(), ContentModel.TYPE_CONTENT))
{
// try and get label from the dictionary
String label = typeDef.getTitle();
// else just use the localname
if (label == null)
{
label = idQName.getLocalName();
}
this.contentTypes.add(new SelectItem(idQName.toString(), label));
}
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(this.contentTypes, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
}
return this.contentTypes;
}
/**
* @return Returns a list of content formats to allow the user to select from
*/
public List<SelectItem> getContentFormats()
{
if (this.contentFormats == null)
{
this.contentFormats = new ArrayList<SelectItem>(80);
ServiceRegistry registry = Repository.getServiceRegistry(FacesContext.getCurrentInstance());
MimetypeService mimetypeService = registry.getMimetypeService();
// get the mime type display names
Map<String, String> mimeTypes = mimetypeService.getDisplaysByMimetype();
for (String mimeType : mimeTypes.keySet())
{
this.contentFormats.add(new SelectItem(mimeType, mimeTypes.get(mimeType)));
}
// make sure the list is sorted by the values
QuickSort sorter = new QuickSort(this.contentFormats, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
// add the "All Formats" constant marker at the top of the list (default selection)
this.contentFormats.add(0, new SelectItem("", Application.getMessage(FacesContext.getCurrentInstance(), MSG_ALL_FORMATS)));
}
return this.contentFormats;
}
// ------------------------------------------------------------------------------
// Action event handlers
/**
* Handler to clear the advanced search screen form details
*/
public void reset(ActionEvent event)
{
this.text = "";
this.mode = MODE_ALL;
this.lookin = LOOKIN_ALL;
this.contentType = null;
this.location = null;
this.category = null;
this.title = null;
this.description = null;
this.author = null;
this.createdDateFrom = null;
this.modifiedDateFrom = null;
this.createdDateChecked = false;
this.modifiedDateChecked = false;
this.customProperties.clear();
}
/**
* Handler to perform a search based on the current criteria
*/
public String search()
{
String outcome = null;
if (this.text != null && this.text.length() != 0)
{
// construct the Search Context and set on the navigation bean
// then simply navigating to the browse screen will cause it pickup the Search Context
SearchContext search = new SearchContext();
search.setText(this.text);
if (this.mode.equals(MODE_ALL))
{
search.setMode(SearchContext.SEARCH_ALL);
}
else if (this.mode.equals(MODE_FILES_TEXT))
{
search.setMode(SearchContext.SEARCH_FILE_NAMES_CONTENTS);
}
else if (this.mode.equals(MODE_FILES))
{
search.setMode(SearchContext.SEARCH_FILE_NAMES);
}
else if (this.mode.equals(MODE_FOLDERS))
{
search.setMode(SearchContext.SEARCH_SPACE_NAMES);
}
// additional attributes search
if (this.description != null && this.description.length() != 0)
{
search.addAttributeQuery(ContentModel.PROP_DESCRIPTION, this.description);
}
if (this.title != null && this.title.length() != 0)
{
search.addAttributeQuery(ContentModel.PROP_TITLE, this.title);
}
if (this.author != null && this.author.length() != 0)
{
search.addAttributeQuery(ContentModel.PROP_CREATOR, this.author);
}
if (this.contentFormat != null && this.contentFormat.length() != 0)
{
search.setMimeType(this.contentFormat);
}
if (this.createdDateChecked == true)
{
SimpleDateFormat df = CachingDateFormat.getDateFormat();
String strCreatedDate = df.format(this.createdDateFrom);
String strCreatedDateTo = df.format(this.createdDateTo);
search.addRangeQuery(ContentModel.PROP_CREATED, strCreatedDate, strCreatedDateTo, true);
}
if (this.modifiedDateChecked == true)
{
SimpleDateFormat df = CachingDateFormat.getDateFormat();
String strModifiedDate = df.format(this.modifiedDateFrom);
String strModifiedDateTo = df.format(this.modifiedDateTo);
search.addRangeQuery(ContentModel.PROP_MODIFIED, strModifiedDate, strModifiedDateTo, true);
}
// walk each of the custom properties add add them as additional attributes
for (String qname : this.customProperties.keySet())
{
Object value = this.customProperties.get(qname);
DataTypeDefinition typeDef = getCustomPropertyLookup().get(qname);
if (typeDef != null)
{
QName typeName = typeDef.getName();
if (DataTypeDefinition.DATE.equals(typeName) || DataTypeDefinition.DATETIME.equals(typeName))
{
// only apply date to search if the user has checked the enable checkbox
if (value != null && Boolean.valueOf(value.toString()) == true)
{
SimpleDateFormat df = CachingDateFormat.getDateFormat();
String strDateFrom = df.format(this.customProperties.get(
UISearchCustomProperties.PREFIX_DATE_FROM + qname));
String strDateTo = df.format(this.customProperties.get(
UISearchCustomProperties.PREFIX_DATE_TO + qname));
search.addRangeQuery(QName.createQName(qname), strDateFrom, strDateTo, true);
}
}
else if (DataTypeDefinition.BOOLEAN.equals(typeName))
{
if (((Boolean)value) == true)
{
search.addFixedValueQuery(QName.createQName(qname), value.toString());
}
}
else if (DataTypeDefinition.NODE_REF.equals(typeName) || DataTypeDefinition.CATEGORY.equals(typeName))
{
if (value != null)
{
search.addFixedValueQuery(QName.createQName(qname), value.toString());
}
}
else if (DataTypeDefinition.INT.equals(typeName) || DataTypeDefinition.LONG.equals(typeName) ||
DataTypeDefinition.FLOAT.equals(typeName) || DataTypeDefinition.DOUBLE.equals(typeName))
{
String strVal = value.toString();
if (strVal != null && strVal.length() != 0)
{
search.addFixedValueQuery(QName.createQName(qname), strVal);
}
}
else
{
// by default use toString() value - this is for text fields and unknown types
String strVal = value.toString();
if (strVal != null && strVal.length() != 0)
{
search.addAttributeQuery(QName.createQName(qname), strVal);
}
}
}
}
// location path search
if (this.lookin.equals(LOOKIN_OTHER) && this.location != null)
{
search.setLocation(SearchContext.getPathFromSpaceRef(
new NodeRef(Repository.getStoreRef(), this.location.getId()), this.locationChildren));
}
// category path search
if (this.category != null)
{
search.setCategories(new String[]{SearchContext.getPathFromSpaceRef(
new NodeRef(Repository.getStoreRef(), this.category.getId()), this.categoryChildren)});
}
// content type restriction
if (this.contentType != null)
{
search.setContentType(this.contentType);
}
// set the Search Context onto the top-level navigator bean
// this causes the browse screen to switch into search results view
this.navigator.setSearchContext(search);
outcome = "browse";
}
return outcome;
}
/**
* @return ClientConfigElement
*/
private ClientConfigElement getClientConfig()
{
if (clientConfigElement == null)
{
ConfigService configService = Application.getConfigService(FacesContext.getCurrentInstance());
clientConfigElement = (ClientConfigElement)configService.getGlobalConfig().getConfigElement(
ClientConfigElement.CONFIG_ELEMENT_ID);
}
return clientConfigElement;
}
/**
* Helper map to lookup custom property QName strings against a DataTypeDefinition
*
* @return custom property lookup Map
*/
private Map<String, DataTypeDefinition> getCustomPropertyLookup()
{
if (customPropertyLookup == null)
{
customPropertyLookup = new HashMap<String, DataTypeDefinition>(7, 1.0f);
List<CustomProperty> customProps = getClientConfig().getCustomProperties();
if (customProps != null)
{
DictionaryService dd = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getDictionaryService();
for (CustomProperty customProp : customProps)
{
PropertyDefinition propDef = null;
QName propQName = Repository.resolveToQName(customProp.Property);
if (customProp.Type != null)
{
QName type = Repository.resolveToQName(customProp.Type);
TypeDefinition typeDef = dd.getType(type);
propDef = typeDef.getProperties().get(propQName);
}
else if (customProp.Aspect != null)
{
QName aspect = Repository.resolveToQName(customProp.Aspect);
AspectDefinition aspectDef = dd.getAspect(aspect);
propDef = aspectDef.getProperties().get(propQName);
}
customPropertyLookup.put(propQName.toString(), propDef.getDataType());
}
}
}
return customPropertyLookup;
}
/**
* Save the state of the progressive panel that was expanded/collapsed
*/
public void expandPanel(ActionEvent event)
{
if (event instanceof ExpandedEvent)
{
this.panels.put(event.getComponent().getId(), ((ExpandedEvent)event).State);
}
}
// ------------------------------------------------------------------------------
// Private data
private static final String MSG_CONTENT = "content";
private static final String MSG_ALL_FORMATS = "all_formats";
private static final String MODE_ALL = "all";
private static final String MODE_FILES_TEXT = "files_text";
private static final String MODE_FILES = "files";
private static final String MODE_FOLDERS = "folders";
private static final String LOOKIN_ALL = "all";
private static final String LOOKIN_OTHER = "other";
/** The NodeService to be used by the bean */
private NodeService nodeService;
/** The NamespaceService to be used by the bean */
private NamespaceService namespaceService;
/** The NavigationBean reference */
private NavigationBean navigator;
/** Client Config reference */
private ClientConfigElement clientConfigElement = null;
/** Progressive panel UI state */
private Map<String, Boolean> panels = new HashMap(5, 1.0f);
/** custom property names to values */
private Map<String, Object> customProperties = new HashMap(5, 1.0f);
/** lookup of custom property QName string to DataTypeDefinition for the property */
private Map<String, DataTypeDefinition> customPropertyLookup = null;
/** content types to for restricting searches */
private List<SelectItem> contentTypes;
/** content format list restricting searches */
private List<SelectItem> contentFormats;
/** content type selection */
private String contentType;
/** content format selection */
private String contentFormat;
/** the text to search for */
private String text = "";
/** search mode */
private String mode = MODE_ALL;
/** folder lookin mode */
private String lookin = LOOKIN_ALL;
/** Space Selector location */
private NodeRef location = null;
/** categories to search */
private NodeRef category = null;
/** title attribute to search */
private String title = null;
/** description attribute to search */
private String description = null;
/** created attribute to search from */
private Date createdDateFrom = null;
/** created attribute to search to */
private Date createdDateTo = null;
/** modified attribute to search from */
private Date modifiedDateFrom = null;
/** modified attribute to search to */
private Date modifiedDateTo = null;
/** true to search location children as well as location */
private boolean locationChildren = true;
/** true to search category children as well as category */
private boolean categoryChildren = true;
/** author (creator) attribute to search */
private String author = null;
private boolean modifiedDateChecked = false;
private boolean createdDateChecked = false;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,688 @@
/*
* 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.web.bean;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.CategoryService;
import org.alfresco.service.cmr.search.CategoryService.Depth;
import org.alfresco.service.cmr.search.CategoryService.Mode;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.IContextListener;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.IBreadcrumbHandler;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.UIBreadcrumb;
import org.alfresco.web.ui.common.component.UIModeList;
import org.alfresco.web.ui.common.component.data.UIRichList;
import org.alfresco.web.ui.repo.component.IRepoBreadcrumbHandler;
import org.apache.log4j.Logger;
/**
* Backing Bean for the Category Management pages.
*
* @author Kevin Roast
*/
public class CategoriesBean implements IContextListener
{
private static final String DEFAULT_OUTCOME = "finish";
private static final String MSG_CATEGORIES = "categories";
private static Logger logger = Logger.getLogger(CategoriesBean.class);
/** The NodeService to be used by the bean */
private NodeService nodeService;
private CategoryService categoryService;
/** Component references */
private UIRichList categoriesRichList;
/** Currently visible category Node*/
private Node category = null;
/** Current category ref */
private NodeRef categoryRef = null;
/** Action category node */
private Node actionCategory = null;
/** Member Count of the linked items of a category */
private Integer members = null;
/** Dialog properties */
private String name = null;
private String description = null;
/** RichList view mode */
private String viewMode = "icons";
/** Category path breadcrumb location */
private List<IBreadcrumbHandler> location = null;
// ------------------------------------------------------------------------------
// Construction
/**
* Default Constructor
*/
public CategoriesBean()
{
UIContextService.getInstance(FacesContext.getCurrentInstance()).registerBean(this);
}
// ------------------------------------------------------------------------------
// Bean property getters and setters
/**
* @param nodeService The NodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param categoryService The CategoryService to set.
*/
public void setCategoryService(CategoryService categoryService)
{
this.categoryService = categoryService;
}
/**
* @param list The categories RichList to set.
*/
public void setCategoriesRichList(UIRichList list)
{
this.categoriesRichList = list;
}
/**
* @return Returns the categories RichList to set.
*/
public UIRichList getCategoriesRichList()
{
return this.categoriesRichList;
}
/**
* @return Returns the description.
*/
public String getDescription()
{
return this.description;
}
/**
* @param description The description to set.
*/
public void setDescription(String description)
{
this.description = description;
}
/**
* @return Returns the viewMode.
*/
public String getViewMode()
{
return this.viewMode;
}
/**
* @param viewMode The viewMode to set.
*/
public void setViewMode(String viewMode)
{
this.viewMode = viewMode;
}
/**
* @return Returns the name.
*/
public String getName()
{
return this.name;
}
/**
* @param name The name to set.
*/
public void setName(String name)
{
this.name = name;
}
/**
* @return Returns the members count for current action category.
*/
public int getMembers()
{
return (this.members != null ? this.members.intValue() : 0);
}
/**
* @return Returns the Node being used for the current action screen.
*/
public Node getActionCategory()
{
return this.actionCategory;
}
/**
* @param actionSpace Set the Node to be used for the current category screen action.
*/
public void setActionCategory(Node node)
{
this.actionCategory = node;
if (node != null)
{
// setup form properties
this.name = node.getName();
this.description = (String)node.getProperties().get(ContentModel.PROP_DESCRIPTION);
this.members = this.categoryService.getChildren(node.getNodeRef(), Mode.MEMBERS, Depth.ANY).size();
}
else
{
this.name = null;
this.description = null;
this.members = 0;
}
}
/**
* @return The currently displayed category as a Node or null if at the root.
*/
public Node getCurrentCategory()
{
if (this.category == null)
{
if (this.categoryRef != null)
{
this.category = new Node(this.categoryRef);
}
}
return this.category;
}
/**
* @return The ID of the currently displayed category or null if at the root.
*/
public String getCurrentCategoryId()
{
if (this.categoryRef != null)
{
return categoryRef.getId();
}
else
{
return null;
}
}
/**
* Set the current category node.
* <p>
* Setting this value causes the UI to update and display the specified node as current.
*
* @param ref The current category node.
*/
public void setCurrentCategory(NodeRef ref)
{
if (logger.isDebugEnabled())
logger.debug("Setting current category: " + ref);
// set the current NodeRef for our UI context operations
this.categoryRef = ref;
// clear current node context
this.category = null;
// inform that the UI needs updating after this change
contextUpdated();
}
/**
* @return Breadcrumb location list
*/
public List<IBreadcrumbHandler> getLocation()
{
if (this.location == null)
{
List<IBreadcrumbHandler> loc = new ArrayList<IBreadcrumbHandler>(8);
loc.add(new CategoryBreadcrumbHandler(null,
Application.getMessage(FacesContext.getCurrentInstance(), MSG_CATEGORIES)));
this.location = loc;
}
return this.location;
}
/**
* @param location Breadcrumb location list
*/
public void setLocation(List<IBreadcrumbHandler> location)
{
this.location = location;
}
/**
* @return The list of categories Nodes to display. Returns the list root categories or the
* list of sub-categories for the current category if set.
*/
public List<Node> getCategories()
{
List<Node> categories;
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context, true);
tx.begin();
Collection<ChildAssociationRef> refs;
if (this.categoryRef == null)
{
// root categories
refs = this.categoryService.getCategories(Repository.getStoreRef(), ContentModel.ASPECT_GEN_CLASSIFIABLE, Depth.IMMEDIATE);
}
else
{
// sub-categories of an existing category
refs = this.categoryService.getChildren(this.categoryRef, Mode.SUB_CATEGORIES, Depth.IMMEDIATE);
}
categories = new ArrayList<Node>(refs.size());
for (ChildAssociationRef child : refs)
{
Node categoryNode = new Node(child.getChildRef());
// force early props init within transaction
categoryNode.getProperties();
categories.add(categoryNode);
}
// commit the transaction
tx.commit();
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {refErr.getNodeRef()}) );
categories = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
catch (Exception err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
categories = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
return categories;
}
/**
* Set the Category to be used for next action dialog
*/
public void setupCategoryAction(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
if (logger.isDebugEnabled())
logger.debug("Setup for action, setting current Category to: " + id);
try
{
// create the node ref, then our node representation
NodeRef ref = new NodeRef(Repository.getStoreRef(), id);
Node node = new Node(ref);
// prepare a node for the action context
setActionCategory(node);
// clear datalist cache ready from return from action dialog
contextUpdated();
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {id}) );
}
}
}
/**
* Clear the category action context - e.g. ready for a Create operation
*/
public void clearCategoryAction(ActionEvent event)
{
setActionCategory(null);
// clear datalist cache ready from return from action dialog
contextUpdated();
}
/**
* Action called when a category folder is clicked.
* Navigate into the category.
*/
public void clickCategory(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
try
{
NodeRef ref = new NodeRef(Repository.getStoreRef(), id);
// refresh UI based on node selection
updateUILocation(ref);
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {id}) );
}
}
}
/**
* Action handler called on Create Category finish button click.
*/
public String finishCreate()
{
String outcome = DEFAULT_OUTCOME;
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
// create category using categoryservice
NodeRef ref;
if (categoryRef == null)
{
ref = this.categoryService.createRootCategory(Repository.getStoreRef(), ContentModel.ASPECT_GEN_CLASSIFIABLE, this.name);
}
else
{
ref = this.categoryService.createCategory(categoryRef, this.name);
}
// apply the titled aspect - for description
Map<QName, Serializable> titledProps = new HashMap<QName, Serializable>(1, 1.0f);
titledProps.put(ContentModel.PROP_DESCRIPTION, this.description);
this.nodeService.addAspect(ref, ContentModel.ASPECT_TITLED, titledProps);
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
outcome = null;
}
return outcome;
}
/**
* Action handler called on Edit Category finish button click.
*/
public String finishEdit()
{
String outcome = DEFAULT_OUTCOME;
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
// update the category node
NodeRef nodeRef = getActionCategory().getNodeRef();
this.nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, this.name);
// apply the titled aspect - for description
if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TITLED) == false)
{
Map<QName, Serializable> titledProps = new HashMap<QName, Serializable>(1, 1.0f);
titledProps.put(ContentModel.PROP_DESCRIPTION, this.description);
this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_TITLED, titledProps);
}
else
{
this.nodeService.setProperty(nodeRef, ContentModel.PROP_DESCRIPTION, this.description);
}
// commit the transaction
tx.commit();
// edit the node in the breadcrumb if required
List<IBreadcrumbHandler> location = getLocation();
IBreadcrumbHandler handler = location.get(location.size() - 1);
// see if the current breadcrumb location is our node
if ( nodeRef.equals(((IRepoBreadcrumbHandler)handler).getNodeRef()) )
{
// and update with the modified node details
IBreadcrumbHandler newHandler = new CategoryBreadcrumbHandler(
nodeRef, Repository.getNameForNode(nodeService, nodeRef));
location.set(location.size() - 1, newHandler);
}
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
outcome = null;
}
return outcome;
}
/**
* Action handler called on Delete Category finish button click.
*/
public String finishDelete()
{
String outcome = DEFAULT_OUTCOME;
if (getActionCategory() != null)
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
// delete the category node using the nodeservice
NodeRef nodeRef = getActionCategory().getNodeRef();
this.categoryService.deleteCategory(nodeRef);
// commit the transaction
tx.commit();
// remove this node from the breadcrumb if required
List<IBreadcrumbHandler> location = getLocation();
IBreadcrumbHandler handler = location.get(location.size() - 1);
// see if the current breadcrumb location is our node
if ( nodeRef.equals(((IRepoBreadcrumbHandler)handler).getNodeRef()) )
{
location.remove(location.size() - 1);
// now work out which node to set the list to refresh against
if (location.size() != 0)
{
handler = location.get(location.size() - 1);
this.setCurrentCategory(((IRepoBreadcrumbHandler)handler).getNodeRef());
}
}
// clear action context
setActionCategory(null);
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
outcome = null;
}
}
return outcome;
}
/**
* Change the current view mode based on user selection
*
* @param event ActionEvent
*/
public void viewModeChanged(ActionEvent event)
{
UIModeList viewList = (UIModeList)event.getComponent();
// get the view mode ID
setViewMode(viewList.getValue().toString());
}
/**
* Update the breadcrumb with the clicked category location
*/
private void updateUILocation(NodeRef ref)
{
String name = Repository.getNameForNode(this.nodeService, ref);
this.location.add(new CategoryBreadcrumbHandler(ref, name));
this.setCurrentCategory(ref);
}
// ------------------------------------------------------------------------------
// IContextListener implementation
/**
* @see org.alfresco.web.app.context.IContextListener#contextUpdated()
*/
public void contextUpdated()
{
if (logger.isDebugEnabled())
logger.debug("Invalidating Category Management Components...");
// force a requery of the current category ref properties
this.category = null;
// force a requery of the richlist dataset
this.categoriesRichList.setValue(null);
}
// ------------------------------------------------------------------------------
// Inner classes
/**
* Class to handle breadcrumb interaction for Categories pages
*/
private class CategoryBreadcrumbHandler implements IRepoBreadcrumbHandler
{
private static final long serialVersionUID = 3831234653171036630L;
/**
* Constructor
*
* @param NodeRef The NodeRef for this browse navigation element
* @param label Element label
*/
public CategoryBreadcrumbHandler(NodeRef nodeRef, String label)
{
this.label = label;
this.nodeRef = nodeRef;
}
/**
* @see java.lang.Object#toString()
*/
public String toString()
{
return this.label;
}
/**
* @see org.alfresco.web.ui.common.component.IBreadcrumbHandler#navigationOutcome(org.alfresco.web.ui.common.component.UIBreadcrumb)
*/
public String navigationOutcome(UIBreadcrumb breadcrumb)
{
// All category breadcrumb elements relate to a Categiry Node Id
// when selected we set the current category Id and return
setCurrentCategory(this.nodeRef);
setLocation( (List)breadcrumb.getValue() );
return null;
}
public NodeRef getNodeRef()
{
return this.nodeRef;
}
private NodeRef nodeRef;
private String label;
}
}

View File

@@ -0,0 +1,951 @@
/*
* 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.web.bean;
import java.io.File;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.version.VersionModel;
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.app.servlet.DownloadContentServlet;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author Kevin Roast
*/
public class CheckinCheckoutBean
{
// ------------------------------------------------------------------------------
// Bean property getters and setters
/**
* @return Returns the BrowseBean.
*/
public BrowseBean getBrowseBean()
{
return this.browseBean;
}
/**
* @param browseBean The BrowseBean to set.
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
/**
* @return Returns the NodeService.
*/
public NodeService getNodeService()
{
return this.nodeService;
}
/**
* @param nodeService The NodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @return Returns the VersionOperationsService.
*/
public CheckOutCheckInService getVersionOperationsService()
{
return this.versionOperationsService;
}
/**
* @param versionOperationsService The VersionOperationsService to set.
*/
public void setVersionOperationsService(CheckOutCheckInService versionOperationsService)
{
this.versionOperationsService = versionOperationsService;
}
/**
* @return Returns the ContentService.
*/
public ContentService getContentService()
{
return this.contentService;
}
/**
* @param contentService The ContentService to set.
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* @return The document node being used for the current operation
*/
public Node getDocument()
{
return this.document;
}
/**
* @param document The document node to be used for the current operation
*/
public void setDocument(Node document)
{
this.document = document;
}
/**
* @return Returns the working copy Document.
*/
public Node getWorkingDocument()
{
return this.workingDocument;
}
/**
* @param workingDocument The working copy Document to set.
*/
public void setWorkingDocument(Node workingDocument)
{
this.workingDocument = workingDocument;
}
/**
* Determines whether the document being checked in has
* the versionable aspect applied
*
* @return true if the versionable aspect is applied
*/
public boolean isVersionable()
{
return getDocument().hasAspect(ContentModel.ASPECT_VERSIONABLE);
}
/**
* @param keepCheckedOut The keepCheckedOut to set.
*/
public void setKeepCheckedOut(boolean keepCheckedOut)
{
this.keepCheckedOut = keepCheckedOut;
}
/**
* @return Returns the keepCheckedOut.
*/
public boolean getKeepCheckedOut()
{
return this.keepCheckedOut;
}
/**
* @param minorChange The minorChange to set.
*/
public void setMinorChange(boolean minorChange)
{
this.minorChange = minorChange;
}
/**
* @return Returns the minorChange flag.
*/
public boolean getMinorChange()
{
return this.minorChange;
}
/**
* @return Returns the version history notes.
*/
public String getVersionNotes()
{
return this.versionNotes;
}
/**
* @param versionNotes The version history notes to set.
*/
public void setVersionNotes(String versionNotes)
{
this.versionNotes = versionNotes;
}
/**
* @return Returns the selected Space Id.
*/
public NodeRef getSelectedSpaceId()
{
return this.selectedSpaceId;
}
/**
* @param selectedSpaceId The selected Space Id to set.
*/
public void setSelectedSpaceId(NodeRef selectedSpaceId)
{
this.selectedSpaceId = selectedSpaceId;
}
/**
* @return Returns the copy location. Either the current or other space.
*/
public String getCopyLocation()
{
if (this.fileName != null)
{
return CheckinCheckoutBean.COPYLOCATION_OTHER;
}
else
{
return this.copyLocation;
}
}
/**
* @param copyLocation The copy location. Either the current or other space.
*/
public void setCopyLocation(String copyLocation)
{
this.copyLocation = copyLocation;
}
/**
* @return Returns the message to display when a file has been uploaded
*/
public String getFileUploadSuccessMsg()
{
String msg = Application.getMessage(FacesContext.getCurrentInstance(), "file_upload_success");
return MessageFormat.format(msg, new Object[] {getFileName()});
}
/**
* @return Returns the name of the file
*/
public String getFileName()
{
// try and retrieve the file and filename from the file upload bean
// representing the file we previously uploaded.
FacesContext ctx = FacesContext.getCurrentInstance();
FileUploadBean fileBean = (FileUploadBean)ctx.getExternalContext().getSessionMap().
get(FileUploadBean.FILE_UPLOAD_BEAN_NAME);
if (fileBean != null)
{
this.file = fileBean.getFile();
this.fileName = fileBean.getFileName();
}
return this.fileName;
}
/**
* @param fileName The name of the file
*/
public void setFileName(String fileName)
{
this.fileName = fileName;
// we also need to keep the file upload bean in sync
FacesContext ctx = FacesContext.getCurrentInstance();
FileUploadBean fileBean = (FileUploadBean)ctx.getExternalContext().getSessionMap().
get(FileUploadBean.FILE_UPLOAD_BEAN_NAME);
if (fileBean != null)
{
fileBean.setFileName(this.fileName);
}
}
/**
* @return Returns the document content used for HTML in-line editing.
*/
public String getDocumentContent()
{
return this.documentContent;
}
/**
* @param documentContent The document content for HTML in-line editing.
*/
public void setDocumentContent(String documentContent)
{
this.documentContent = documentContent;
}
/**
* @return Returns output from the in-line editor page.
*/
public String getEditorOutput()
{
return this.editorOutput;
}
/**
* @param editorOutput The output from the in-line editor page
*/
public void setEditorOutput(String editorOutput)
{
this.editorOutput = editorOutput;
}
// ------------------------------------------------------------------------------
// Navigation action event handlers
/**
* Action event called by all actions that need to setup a Content Document context on the
* CheckinCheckoutBean before an action page/wizard is called. The context will be a Node in
* setDocument() which can be retrieved on action pages via getDocument().
*
* @param event ActionEvent
*/
public void setupContentAction(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
setupContentDocument(id);
}
else
{
setDocument(null);
}
clearUpload();
}
/**
* Setup a content document node context
*
* @param id GUID of the node to setup as the content document context
*
* @return The Node
*/
private Node setupContentDocument(String id)
{
if (logger.isDebugEnabled())
logger.debug("Setup for action, setting current document to: " + id);
Node node = null;
try
{
// create the node ref, then our node representation
NodeRef ref = new NodeRef(Repository.getStoreRef(), id);
node = new Node(ref);
// create content URL to the content download servlet with ID and expected filename
// the myfile part will be ignored by the servlet but gives the browser a hint
String url = DownloadContentServlet.generateDownloadURL(ref, node.getName());
node.getProperties().put("url", url);
node.getProperties().put("workingCopy", node.hasAspect(ContentModel.ASPECT_WORKING_COPY));
node.getProperties().put("fileType32", Utils.getFileTypeImage(node.getName(), false));
// remember the document
setDocument(node);
// refresh the UI, calling this method now is fine as it basically makes sure certain
// beans clear the state - so when we finish here other beans will have been reset
UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {id}) );
}
return node;
}
/**
* Action called upon completion of the Check Out file page
*/
public String checkoutFile()
{
String outcome = null;
UserTransaction tx = null;
Node node = getDocument();
if (node != null)
{
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (logger.isDebugEnabled())
logger.debug("Trying to checkout content node Id: " + node.getId());
// checkout the node content to create a working copy
if (logger.isDebugEnabled())
{
logger.debug("Checkout copy location: " + getCopyLocation());
logger.debug("Selected Space Id: " + this.selectedSpaceId);
}
NodeRef workingCopyRef;
if (getCopyLocation().equals(COPYLOCATION_OTHER) && this.selectedSpaceId != null)
{
// checkout to a arbituary parent Space
NodeRef destRef = this.selectedSpaceId;
ChildAssociationRef childAssocRef = this.nodeService.getPrimaryParent(destRef);
workingCopyRef = this.versionOperationsService.checkout(node.getNodeRef(),
destRef, ContentModel.ASSOC_CONTAINS, childAssocRef.getQName());
}
else
{
workingCopyRef = this.versionOperationsService.checkout(node.getNodeRef());
}
// set the working copy Node instance
Node workingCopy = new Node(workingCopyRef);
setWorkingDocument(workingCopy);
// create content URL to the content download servlet with ID and expected filename
// the myfile part will be ignored by the servlet but gives the browser a hint
String url = DownloadContentServlet.generateDownloadURL(workingCopyRef, workingCopy.getName());
workingCopy.getProperties().put("url", url);
workingCopy.getProperties().put("fileType32", Utils.getFileTypeImage(workingCopy.getName(), false));
// commit the transaction
tx.commit();
// show the page that display the checkout link
outcome = "checkoutFileLink";
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(Application.getMessage(
FacesContext.getCurrentInstance(), MSG_ERROR_CHECKOUT) + err.getMessage(), err);
}
}
else
{
logger.warn("WARNING: checkoutFile called without a current Document!");
}
return outcome;
}
/**
* Action called upon completion of the Check Out file Link download page
*/
public String checkoutFileOK()
{
String outcome = null;
Node node = getWorkingDocument();
if (node != null)
{
// clean up and clear action context
clearUpload();
setDocument(null);
setWorkingDocument(null);
outcome = "browse";
}
else
{
logger.warn("WARNING: checkoutFileOK called without a current WorkingDocument!");
}
return outcome;
}
/**
* Action called upon completion of the Edit File download page
*/
public String editFileOK()
{
String outcome = null;
Node node = getDocument();
if (node != null)
{
// clean up and clear action context
clearUpload();
setDocument(null);
setWorkingDocument(null);
outcome = "browse";
}
else
{
logger.warn("WARNING: editFileOK called without a current Document!");
}
return outcome;
}
/**
* Action handler called to calculate which editing screen to display based on the mimetype
* of a document. If appropriate, the in-line editing screen will be shown.
*/
public void editFile(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
Node node = setupContentDocument(id);
// detect the inline editing aspect to see which edit mode to use
if (node.hasAspect(ContentModel.ASPECT_INLINEEDITABLE) &&
node.getProperties().get(ContentModel.PROP_EDITINLINE) != null &&
((Boolean)node.getProperties().get(ContentModel.PROP_EDITINLINE)).booleanValue() == true)
{
// retrieve the content reader for this node
ContentReader reader = getContentService().getReader(node.getNodeRef(), ContentModel.PROP_CONTENT);
String mimetype = reader.getMimetype();
// calculate which editor screen to display
if (MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(mimetype) ||
MimetypeMap.MIMETYPE_XML.equals(mimetype) ||
MimetypeMap.MIMETYPE_TEXT_CSS.equals(mimetype))
{
// make content available to the editing screen
if (reader != null)
{
setEditorOutput(reader.getContentString());
}
else
{
setEditorOutput("");
}
// navigate to appropriate screen
FacesContext fc = FacesContext.getCurrentInstance();
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "editTextInline");
}
else
{
// make content available to the editing screen
if (reader != null)
{
setDocumentContent(reader.getContentString());
}
else
{
setDocumentContent("");
}
setEditorOutput(null);
// navigate to appropriate screen
FacesContext fc = FacesContext.getCurrentInstance();
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "editHtmlInline");
}
}
else
{
// normal downloadable document
FacesContext fc = FacesContext.getCurrentInstance();
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "editFile");
}
}
}
/**
* Action handler called to set the content of a node from an inline editing page.
*/
public String editInlineOK()
{
String outcome = null;
UserTransaction tx = null;
Node node = getDocument();
if (node != null)
{
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (logger.isDebugEnabled())
logger.debug("Trying to update content node Id: " + node.getId());
// get an updating writer that we can use to modify the content on the current node
ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true);
writer.putContent(this.editorOutput);
// commit the transaction
tx.commit();
// clean up and clear action context
clearUpload();
setDocument(null);
setDocumentContent(null);
setEditorOutput(null);
outcome = "browse";
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(Application.getMessage(
FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE) + err.getMessage());
}
}
else
{
logger.warn("WARNING: editInlineOK called without a current Document!");
}
return outcome;
}
/**
* Action to undo the checkout of a document just checked out from the checkout screen.
*/
public String undoCheckout()
{
String outcome = null;
Node node = getWorkingDocument();
if (node != null)
{
try
{
// try to cancel checkout of the working copy
this.versionOperationsService.cancelCheckout(node.getNodeRef());
clearUpload();
outcome = "browse";
}
catch (Throwable err)
{
Utils.addErrorMessage(Application.getMessage(
FacesContext.getCurrentInstance(), MSG_ERROR_CANCELCHECKOUT) + err.getMessage(), err);
}
}
else
{
logger.warn("WARNING: undoCheckout called without a current WorkingDocument!");
}
return outcome;
}
/**
* Action to undo the checkout of a locked document. This document may either by the original copy
* or the working copy node. Therefore calculate which it is, if the working copy is found then
* we simply cancel checkout on that document. If the original copy is found then we need to find
* the appropriate working copy and perform the action on that node.
*/
public String undoCheckoutFile()
{
String outcome = null;
Node node = getDocument();
if (node != null)
{
try
{
if (node.hasAspect(ContentModel.ASPECT_WORKING_COPY))
{
this.versionOperationsService.cancelCheckout(node.getNodeRef());
}
else if (node.hasAspect(ContentModel.ASPECT_LOCKABLE))
{
// TODO: find the working copy for this document and cancel the checkout on it
// is this possible? as currently only the workingcopy aspect has the copyReference
// attribute - this means we cannot find out where the copy is to cancel it!
// can we construct an XPath node lookup?
throw new RuntimeException("NOT IMPLEMENTED");
}
else
{
throw new IllegalStateException("Node supplied for undo checkout has neither Working Copy or Locked aspect!");
}
clearUpload();
outcome = "browse";
}
catch (Throwable err)
{
Utils.addErrorMessage(MSG_ERROR_CANCELCHECKOUT + err.getMessage(), err);
}
}
else
{
logger.warn("WARNING: undoCheckout called without a current WorkingDocument!");
}
return outcome;
}
/**
* Action called upon completion of the Check In file page
*/
public String checkinFileOK()
{
String outcome = null;
UserTransaction tx = null;
// NOTE: for checkin the document node _is_ the working document!
Node node = getDocument();
if (node != null && (getCopyLocation().equals(COPYLOCATION_CURRENT) || this.getFileName() != null))
{
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (logger.isDebugEnabled())
logger.debug("Trying to checkin content node Id: " + node.getId());
// we can either checkin the content from the current working copy node
// which would have been previously updated by the user
String contentUrl;
String mimetype;
if (getCopyLocation().equals(COPYLOCATION_CURRENT))
{
ContentData contentData = (ContentData) node.getProperties().get(ContentModel.PROP_CONTENT);
contentUrl = (contentData == null ? null : contentData.getContentUrl());
}
// or specify a specific file as the content instead
else
{
// add the content to an anonymous but permanent writer location
// we can then retrieve the URL to the content to to be set on the node during checkin
ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, false);
// TODO: Adjust the mimetype
writer.putContent(this.file);
contentUrl = writer.getContentUrl();
}
if (contentUrl == null || contentUrl.length() == 0)
{
throw new IllegalStateException("Content URL is empty for specified working copy content node!");
}
// add version history text to props
Map<String, Serializable> props = new HashMap<String, Serializable>(1, 1.0f);
props.put(Version.PROP_DESCRIPTION, this.versionNotes);
// set the flag for minor or major change
if (this.minorChange)
{
props.put(VersionModel.PROP_VERSION_TYPE, VersionType.MINOR);
}
else
{
props.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR);
}
NodeRef originalDoc = this.versionOperationsService.checkin(
node.getNodeRef(),
props,
contentUrl,
this.keepCheckedOut);
// commit the transaction
tx.commit();
// clear action context
setDocument(null);
clearUpload();
outcome = "browse";
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(Application.getMessage(
FacesContext.getCurrentInstance(), MSG_ERROR_CHECKIN) + err.getMessage(), err);
}
}
else
{
logger.warn("WARNING: checkinFileOK called without a current Document!");
}
return outcome;
}
/**
* Action called upon completion of the Update File page
*/
public String updateFileOK()
{
String outcome = null;
UserTransaction tx = null;
// NOTE: for update the document node _is_ the working document!
Node node = getDocument();
if (node != null && this.getFileName() != null)
{
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (logger.isDebugEnabled())
logger.debug("Trying to update content node Id: " + node.getId());
// get an updating writer that we can use to modify the content on the current node
ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true);
writer.putContent(this.file);
// commit the transaction
tx.commit();
// clear action context
setDocument(null);
clearUpload();
outcome = "browse";
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(Application.getMessage(
FacesContext.getCurrentInstance(), MSG_ERROR_UPDATE) + err.getMessage(), err);
}
}
else
{
logger.warn("WARNING: updateFileOK called without a current Document!");
}
return outcome;
}
/**
* Deals with the cancel button being pressed on the check in file page
*/
public String cancel()
{
// reset the state
clearUpload();
return "browse";
}
/**
* Clear form state and upload file bean
*/
private void clearUpload()
{
// delete the temporary file we uploaded earlier
if (this.file != null)
{
this.file.delete();
}
this.file = null;
this.fileName = null;
this.keepCheckedOut = false;
this.minorChange = true;
this.copyLocation = COPYLOCATION_CURRENT;
this.versionNotes = "";
this.selectedSpaceId = null;
// remove the file upload bean from the session
FacesContext ctx = FacesContext.getCurrentInstance();
ctx.getExternalContext().getSessionMap().remove(FileUploadBean.FILE_UPLOAD_BEAN_NAME);
}
// ------------------------------------------------------------------------------
// Private data
private static Log logger = LogFactory.getLog(CheckinCheckoutBean.class);
/** I18N messages */
private static final String MSG_ERROR_CHECKIN = "error_checkin";
private static final String MSG_ERROR_CANCELCHECKOUT = "error_cancel_checkout";
private static final String MSG_ERROR_UPDATE = "error_update";
private static final String MSG_ERROR_CHECKOUT = "error_checkout";
/** constants for copy location selection */
private static final String COPYLOCATION_CURRENT = "current";
private static final String COPYLOCATION_OTHER = "other";
/** The current document */
private Node document;
/** The working copy of the document we are checking out */
private Node workingDocument;
/** Content of the document used for HTML in-line editing */
private String documentContent;
/** Content of the document returned from in-line editing */
private String editorOutput;
/** transient form and upload properties */
private File file;
private String fileName;
private boolean keepCheckedOut = false;
private boolean minorChange = true;
private String copyLocation = COPYLOCATION_CURRENT;
private String versionNotes = "";
private NodeRef selectedSpaceId = null;
/** The BrowseBean to be used by the bean */
private BrowseBean browseBean;
/** The NodeService to be used by the bean */
private NodeService nodeService;
/** The VersionOperationsService to be used by the bean */
private CheckOutCheckInService versionOperationsService;
/** The ContentService to be used by the bean */
private ContentService contentService;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,353 @@
/*
* 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.web.bean;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import javax.transaction.UserTransaction;
import org.alfresco.config.Config;
import org.alfresco.config.ConfigLookupContext;
import org.alfresco.config.ConfigService;
import org.alfresco.model.ContentModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.config.PropertySheetConfigElement;
import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
import org.alfresco.web.ui.common.Utils;
import org.springframework.web.jsf.FacesContextUtils;
/**
* Backing bean for the edit document properties dialog
*
* @author gavinc
*/
public class DocumentPropertiesBean
{
private static final String TEMP_PROP_MIMETYPE = "mimetype";
private NodeService nodeService;
private FileFolderService fileFolderService;
private DictionaryService dictionaryService;
private BrowseBean browseBean;
private List<SelectItem> contentTypes;
private Node editableNode;
private Boolean hasOtherProperties;
/**
* Returns the node being edited
*
* @return The node being edited
*/
public Node getEditableNode()
{
return this.editableNode;
}
/**
* Event handler called to setup the document for property editing
*
* @param event The event
*/
public void setupDocumentForAction(ActionEvent event)
{
this.editableNode = new Node(this.browseBean.getDocument().getNodeRef());
// special case for Mimetype - since this is a sub-property of the ContentData object
// we must extract it so it can be edited in the client, then we check for it later
// and create a new ContentData object to wrap it and it's associated URL
ContentData content = (ContentData)this.editableNode.getProperties().get(ContentModel.PROP_CONTENT);
if (content != null)
{
this.editableNode.getProperties().put(TEMP_PROP_MIMETYPE, content.getMimetype());
}
this.hasOtherProperties = null;
}
/**
* Event handler used to save the edited properties back to the repository
*
* @return The outcome
*/
public String save()
{
String outcome = "cancel";
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
NodeRef nodeRef = this.browseBean.getDocument().getNodeRef();
Map<String, Object> props = this.editableNode.getProperties();
// get the name and move the node as necessary
String name = (String) props.get(ContentModel.PROP_NAME);
if (name != null)
{
fileFolderService.rename(nodeRef, name);
}
Map<QName, Serializable> properties = this.nodeService.getProperties(nodeRef);
// we need to put all the properties from the editable bag back into
// the format expected by the repository
// but first extract and deal with the special mimetype property for ContentData
String mimetype = (String)props.get(TEMP_PROP_MIMETYPE);
if (mimetype != null)
{
// remove temporary prop from list so it isn't saved with the others
props.remove(TEMP_PROP_MIMETYPE);
ContentData contentData = (ContentData)props.get(ContentModel.PROP_CONTENT);
if (contentData != null)
{
contentData = ContentData.setMimetype(contentData, mimetype);
props.put(ContentModel.PROP_CONTENT.toString(), contentData);
}
}
// add the remaining properties
Iterator<String> iterProps = props.keySet().iterator();
while (iterProps.hasNext())
{
String propName = iterProps.next();
QName qname = QName.createQName(propName);
// make sure the property is represented correctly
Serializable propValue = (Serializable)props.get(propName);
PropertyDefinition propDef = this.dictionaryService.getProperty(qname);
properties.put(qname, propValue);
}
// send the properties back to the repository
this.nodeService.setProperties(this.browseBean.getDocument().getNodeRef(), properties);
// we also need to persist any association changes that may have been made
// add any associations added in the UI
Map<String, Map<String, AssociationRef>> addedAssocs = this.editableNode.getAddedAssociations();
for (Map<String, AssociationRef> typedAssoc : addedAssocs.values())
{
for (AssociationRef assoc : typedAssoc.values())
{
this.nodeService.createAssociation(assoc.getSourceRef(), assoc.getTargetRef(), assoc.getTypeQName());
}
}
// remove any association removed in the UI
Map<String, Map<String, AssociationRef>> removedAssocs = this.editableNode.getRemovedAssociations();
for (Map<String, AssociationRef> typedAssoc : removedAssocs.values())
{
for (AssociationRef assoc : typedAssoc.values())
{
this.nodeService.removeAssociation(assoc.getSourceRef(), assoc.getTargetRef(), assoc.getTypeQName());
}
}
// add any child associations added in the UI
Map<String, Map<String, ChildAssociationRef>> addedChildAssocs = this.editableNode.getAddedChildAssociations();
for (Map<String, ChildAssociationRef> typedAssoc : addedChildAssocs.values())
{
for (ChildAssociationRef assoc : typedAssoc.values())
{
this.nodeService.addChild(assoc.getParentRef(), assoc.getChildRef(), assoc.getTypeQName(), assoc.getTypeQName());
}
}
// remove any child association removed in the UI
Map<String, Map<String, ChildAssociationRef>> removedChildAssocs = this.editableNode.getRemovedChildAssociations();
for (Map<String, ChildAssociationRef> typedAssoc : removedChildAssocs.values())
{
for (ChildAssociationRef assoc : typedAssoc.values())
{
this.nodeService.removeChild(assoc.getParentRef(), assoc.getChildRef());
}
}
// commit the transaction
tx.commit();
// set the outcome to refresh
outcome = "finish";
// reset the document held by the browse bean as it's just been updated
this.browseBean.getDocument().reset();
}
catch (FileExistsException e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
// print status message
String statusMsg = MessageFormat.format(
Application.getMessage(
FacesContext.getCurrentInstance(), "error_exists"),
e.getExisting().getName());
Utils.addErrorMessage(statusMsg);
// no outcome
outcome = null;
}
catch (InvalidNodeRefException err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {this.browseBean.getDocument().getId()}) );
// this failure means the node no longer exists - we cannot show the doc properties screen
outcome = "browse";
}
catch (Exception e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), e.getMessage()), e);
}
return outcome;
}
public Map<String, Object> getProperties()
{
return this.editableNode.getProperties();
}
/**
* @return Returns a list of content types to allow the user to select from
*/
public List<SelectItem> getContentTypes()
{
if (this.contentTypes == null)
{
this.contentTypes = new ArrayList<SelectItem>(80);
ServiceRegistry registry = Repository.getServiceRegistry(FacesContext.getCurrentInstance());
MimetypeService mimetypeService = registry.getMimetypeService();
// get the mime type display names
Map<String, String> mimeTypes = mimetypeService.getDisplaysByMimetype();
for (String mimeType : mimeTypes.keySet())
{
this.contentTypes.add(new SelectItem(mimeType, mimeTypes.get(mimeType)));
}
// make sure the list is sorted by the values
QuickSort sorter = new QuickSort(this.contentTypes, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
return this.contentTypes;
}
/**
* Determines whether this document has any other properties other than the
* default set to display to the user.
*
* @return true of there are properties to show, false otherwise
*/
public boolean getOtherPropertiesPresent()
{
if (this.hasOtherProperties == null)
{
// we need to use the config service to see whether there are any
// editable properties configured for this document.
ConfigService configSvc = (ConfigService)FacesContextUtils.getRequiredWebApplicationContext(
FacesContext.getCurrentInstance()).getBean(Application.BEAN_CONFIG_SERVICE);
Config configProps = configSvc.getConfig(this.editableNode, new ConfigLookupContext("edit-properties"));
PropertySheetConfigElement propsToDisplay = (PropertySheetConfigElement)configProps.
getConfigElement("property-sheet");
this.hasOtherProperties = Boolean.valueOf(propsToDisplay != null);
}
return this.hasOtherProperties.booleanValue();
}
/**
* @return Returns the nodeService.
*/
public NodeService getNodeService()
{
return this.nodeService;
}
/**
* @param nodeService The nodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param fileFolderService the file and folder model-specific functions
*/
public void setFileFolderService(FileFolderService fileFolderService)
{
this.fileFolderService = fileFolderService;
}
/**
* Sets the DictionaryService to use when persisting metadata
*
* @param dictionaryService The DictionaryService
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* @return The BrowseBean
*/
public BrowseBean getBrowseBean()
{
return this.browseBean;
}
/**
* @param browseBean The BrowseBean to set.
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
}

View File

@@ -0,0 +1,136 @@
/*
* 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.web.bean;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.ServletException;
/**
* Bean used by the error page, holds the last exception to be thrown by the system
*
* @author gavinc
*/
public class ErrorBean
{
public static final String ERROR_BEAN_NAME = "alfresco.ErrorBean";
private String returnPage;
private Throwable lastError;
/**
* @return Returns the page to go back to after the error has been displayed
*/
public String getReturnPage()
{
return returnPage;
}
/**
* @param returnPage The page to return to after showing the error
*/
public void setReturnPage(String returnPage)
{
this.returnPage = returnPage;
}
/**
* @return Returns the lastError.
*/
public Throwable getLastError()
{
return lastError;
}
/**
* @param lastError The lastError to set.
*/
public void setLastError(Throwable lastError)
{
this.lastError = lastError;
}
/**
* @return Returns the last error to occur in string form
*/
public String getLastErrorMessage()
{
String message = "No error currently stored";
if (this.lastError != null)
{
StringBuilder builder = null;
Throwable cause = null;
if (this.lastError instanceof ServletException &&
((ServletException)this.lastError).getRootCause() != null)
{
// servlet exception puts the actual error in root cause!!
Throwable actualError = ((ServletException)this.lastError).getRootCause();
builder = new StringBuilder(actualError.toString());
cause = actualError.getCause();
}
else
{
builder = new StringBuilder(this.lastError.toString());
cause = this.lastError.getCause();
}
while (cause != null)
{
builder.append("<br/><br/>caused by:<br/>");
builder.append(cause.toString());
if (cause instanceof ServletException &&
((ServletException)cause).getRootCause() != null)
{
cause = ((ServletException)cause).getRootCause();
}
else
{
cause = cause.getCause();
}
}
message = builder.toString();
}
return message;
}
/**
* @return Returns the stack trace for the last error
*/
public String getStackTrace()
{
StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(stringWriter);
if (this.lastError instanceof ServletException &&
((ServletException)this.lastError).getRootCause() != null)
{
Throwable actualError = ((ServletException)this.lastError).getRootCause();
actualError.printStackTrace(writer);
}
else
{
this.lastError.printStackTrace(writer);
}
return stringWriter.toString().replaceAll("\r\n", "<br/>");
}
}

View File

@@ -0,0 +1,330 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the GNU Lesser General Public License as
* published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.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.web.bean;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.transaction.UserTransaction;
import org.alfresco.repo.action.executer.ExporterActionExecuter;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Backing bean implementation for the Export dialog.
*
* @author gavinc
*/
public class ExportBean
{
private static final Log logger = LogFactory.getLog(ExportBean.class);
private static final String ALL_SPACES = "all";
private static final String CURRENT_SPACE = "current";
private static final String DEFAULT_OUTCOME = "browse";
private static final String MSG_ERROR = "error_export";
private BrowseBean browseBean;
private NodeService nodeService;
private ActionService actionService;
private String packageName;
private String encoding = "UTF-8";
private String mode = CURRENT_SPACE;
private NodeRef destination;
private boolean includeChildren = true;
private boolean runInBackground = true;
private boolean includeSelf;
/**
* Performs the export operation using the current state of the bean
*
* @return The outcome
*/
public String export()
{
if (logger.isDebugEnabled())
logger.debug("Called export for " + this.mode + " with package name: " + this.packageName);
String outcome = DEFAULT_OUTCOME;
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
// build the action params map based on the bean's current state
Map<String, Serializable> params = new HashMap<String, Serializable>(5);
params.put(ExporterActionExecuter.PARAM_STORE, Repository.getStoreRef().toString());
params.put(ExporterActionExecuter.PARAM_PACKAGE_NAME, this.packageName);
params.put(ExporterActionExecuter.PARAM_ENCODING, this.encoding);
params.put(ExporterActionExecuter.PARAM_DESTINATION_FOLDER, this.destination);
params.put(ExporterActionExecuter.PARAM_INCLUDE_CHILDREN, new Boolean(includeChildren));
params.put(ExporterActionExecuter.PARAM_INCLUDE_SELF, new Boolean(includeSelf));
// build the action to execute
Action action = this.actionService.createAction(ExporterActionExecuter.NAME, params);
action.setExecuteAsynchronously(this.runInBackground);
// get the appropriate node
NodeRef startNode = null;
if (this.mode.equals(ALL_SPACES))
{
startNode = this.nodeService.getRootNode(Repository.getStoreRef());
}
else
{
startNode = this.browseBean.getActionSpace().getNodeRef();
}
// execute the action on the relevant node
this.actionService.executeAction(action, startNode);
if (logger.isDebugEnabled())
{
logger.debug("Executed export action with action params of " + params);
}
// commit the transaction
tx.commit();
// reset the bean
reset();
}
catch (Exception e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), MSG_ERROR), e.toString()), e);
outcome = null;
}
return outcome;
}
/**
* Action called when the dialog is cancelled, just resets the bean's state
*
* @return The outcome
*/
public String cancel()
{
reset();
return DEFAULT_OUTCOME;
}
/**
* Resets the dialog state back to the default
*/
public void reset()
{
this.packageName = null;
this.mode = CURRENT_SPACE;
this.destination = null;
this.includeChildren = true;
this.includeSelf = false;
this.runInBackground = true;
}
/**
* Returns the package name for the export
*
* @return The export package name
*/
public String getPackageName()
{
return this.packageName;
}
/**
* Sets the package name for the export
*
* @param packageName The export package name
*/
public void setPackageName(String packageName)
{
this.packageName = packageName;
}
/**
* The destination for the export as a NodeRef
*
* @return The destination
*/
public NodeRef getDestination()
{
return this.destination;
}
/**
* Sets the destination for the export
*
* @param destination The destination for the export
*/
public void setDestination(NodeRef destination)
{
this.destination = destination;
}
/**
* Determines whether the export will include child spaces
*
* @return true includes children
*/
public boolean getIncludeChildren()
{
return this.includeChildren;
}
/**
* Sets whether child spaces are included in the export
*
* @param includeChildren true to include the child spaces
*/
public void setIncludeChildren(boolean includeChildren)
{
this.includeChildren = includeChildren;
}
/**
* Determines whether the export will include the space itself
*
* @return true includes the space being exported from
*/
public boolean getIncludeSelf()
{
return this.includeSelf;
}
/**
* Sets whether the space itself is included in the export
*
* @param includeSelf true to include the space itself
*/
public void setIncludeSelf(boolean includeSelf)
{
this.includeSelf = includeSelf;
}
/**
* Determines whether to export only the current space or all spaces
*
* @return "all" to export all space and "current" to export the current space
*/
public String getMode()
{
return this.mode;
}
/**
* Sets whether to export the current space or all spaces
*
* @param mode "all" to export all space and "current" to export the current space
*/
public void setMode(String mode)
{
this.mode = mode;
}
/**
* Returns the encoding to use for the export
*
* @return The encoding
*/
public String getEncoding()
{
return this.encoding;
}
/**
* Sets the encoding to use for the export package
*
* @param encoding The encoding
*/
public void setEncoding(String encoding)
{
this.encoding = encoding;
}
/**
* Determines whether the import should run in the background
*
* @return true means the import will run in the background
*/
public boolean getRunInBackground()
{
return this.runInBackground;
}
/**
* Determines whether the import will run in the background
*
* @param runInBackground true to run the import in the background
*/
public void setRunInBackground(boolean runInBackground)
{
this.runInBackground = runInBackground;
}
/**
* Sets the BrowseBean instance to use to retrieve the current document
*
* @param browseBean BrowseBean instance
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
/**
* Sets the action service
*
* @param actionService the action service
*/
public void setActionService(ActionService actionService)
{
this.actionService = actionService;
}
/**
* Sets the node service
*
* @param nodeService the node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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.web.bean;
import java.io.File;
/**
* Bean to hold the results of a file upload
*
* @author gavinc
*/
public final class FileUploadBean
{
public static final String FILE_UPLOAD_BEAN_NAME = "alfresco.UploadBean";
private File file;
private String fileName;
private String filePath;
/**
* @return Returns the file
*/
public File getFile()
{
return file;
}
/**
* @param file The file to set
*/
public void setFile(File file)
{
this.file = file;
}
/**
* @return Returns the name of the file uploaded
*/
public String getFileName()
{
return fileName;
}
/**
* @param fileName The name of the uploaded file
*/
public void setFileName(String fileName)
{
this.fileName = fileName;
}
/**
* @return Returns the path of the file uploaded
*/
public String getFilePath()
{
return filePath;
}
/**
* @param filePath The file path of the uploaded file
*/
public void setFilePath(String filePath)
{
this.filePath = filePath;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,322 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the GNU Lesser General Public License as
* published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.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.web.bean;
import java.io.File;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.executer.ImporterActionExecuter;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Backing bean implementation for the Import dialog.
*
* @author gavinc
*/
public class ImportBean
{
private static final Log logger = LogFactory.getLog(ImportBean.class);
private static final String DEFAULT_OUTCOME = "browse";
private static final String MSG_ERROR = "error_import";
private static final String MSG_ERROR_NO_FILE = "error_import_no_file";
private static final String MSG_ERROR_EMPTY_FILE = "error_import_empty_file";
private BrowseBean browseBean;
private NodeService nodeService;
private ActionService actionService;
private ContentService contentService;
private File file;
private String fileName;
private String encoding = "UTF-8";
private boolean runInBackground = true;
/**
* Performs the import operation using the current state of the bean
*
* @return The outcome
*/
public String performImport()
{
String outcome = DEFAULT_OUTCOME;
if (logger.isDebugEnabled())
logger.debug("Called import for file: " + this.file);
if (this.file != null && this.file.exists())
{
// check the file actually has contents
if (this.file.length() > 0)
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
// first of all we need to add the uploaded ACP file to the repository
NodeRef acpNodeRef = addACPToRepository(context);
// build the action params map based on the bean's current state
Map<String, Serializable> params = new HashMap<String, Serializable>(3);
params.put(ImporterActionExecuter.PARAM_DESTINATION_FOLDER, this.browseBean.getActionSpace().getNodeRef());
params.put(ImporterActionExecuter.PARAM_ENCODING, this.encoding);
// build the action to execute
Action action = this.actionService.createAction(ImporterActionExecuter.NAME, params);
action.setExecuteAsynchronously(this.runInBackground);
// execute the action on the ACP file
this.actionService.executeAction(action, acpNodeRef);
if (logger.isDebugEnabled())
{
logger.debug("Executed import action with action params of " + params);
}
// commit the transaction
tx.commit();
// reset the bean
reset();
}
catch (Exception e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), MSG_ERROR), e.toString()), e);
outcome = null;
}
}
else
{
Utils.addErrorMessage(Application.getMessage(FacesContext.getCurrentInstance(), MSG_ERROR_EMPTY_FILE));
outcome = null;
}
}
else
{
Utils.addErrorMessage(Application.getMessage(FacesContext.getCurrentInstance(), MSG_ERROR_NO_FILE));
outcome = null;
}
return outcome;
}
/**
* Action called when the dialog is cancelled, just resets the bean's state
*
* @return The outcome
*/
public String cancel()
{
reset();
return DEFAULT_OUTCOME;
}
/**
* Resets the dialog state back to the default
*/
public void reset()
{
this.file = null;
this.fileName = null;
this.runInBackground = true;
// delete the temporary file we uploaded earlier
if (this.file != null)
{
this.file.delete();
}
// remove the file upload bean from the session
FacesContext ctx = FacesContext.getCurrentInstance();
ctx.getExternalContext().getSessionMap().remove(FileUploadBean.FILE_UPLOAD_BEAN_NAME);
}
/**
* @return Returns the message to display when a file has been uploaded
*/
public String getFileUploadSuccessMsg()
{
String msg = Application.getMessage(FacesContext.getCurrentInstance(), "file_upload_success");
return MessageFormat.format(msg, new Object[] {getFileName()});
}
/**
* @return Returns the name of the file
*/
public String getFileName()
{
// try and retrieve the file and filename from the file upload bean
// representing the file we previously uploaded.
FacesContext ctx = FacesContext.getCurrentInstance();
FileUploadBean fileBean = (FileUploadBean)ctx.getExternalContext().getSessionMap().
get(FileUploadBean.FILE_UPLOAD_BEAN_NAME);
if (fileBean != null)
{
this.fileName = fileBean.getFileName();
this.file = fileBean.getFile();
}
return this.fileName;
}
/**
* Returns the encoding to use for the export
*
* @return The encoding
*/
public String getEncoding()
{
return this.encoding;
}
/**
* Sets the encoding to use for the export package
*
* @param encoding The encoding
*/
public void setEncoding(String encoding)
{
this.encoding = encoding;
}
/**
* Determines whether the import should run in the background
*
* @return true means the import will run in the background
*/
public boolean getRunInBackground()
{
return this.runInBackground;
}
/**
* Determines whether the import will run in the background
*
* @param runInBackground true to run the import in the background
*/
public void setRunInBackground(boolean runInBackground)
{
this.runInBackground = runInBackground;
}
/**
* Sets the BrowseBean instance to use to retrieve the current document
*
* @param browseBean BrowseBean instance
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
/**
* Sets the action service
*
* @param actionService the action service
*/
public void setActionService(ActionService actionService)
{
this.actionService = actionService;
}
/**
* Sets the node service
*
* @param nodeService the node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Sets the content service
*
* @param contentService the content service
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* Adds the uploaded ACP file to the repository
*
* @param context Faces context
* @return NodeRef representing the ACP file in the repository
*/
private NodeRef addACPToRepository(FacesContext context)
{
// set the name for the new node
Map<QName, Serializable> contentProps = new HashMap<QName, Serializable>(1);
contentProps.put(ContentModel.PROP_NAME, this.fileName);
// create the node to represent the zip file
String assocName = QName.createValidLocalName(this.fileName);
ChildAssociationRef assocRef = this.nodeService.createNode(
this.browseBean.getActionSpace().getNodeRef(), ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, assocName),
ContentModel.TYPE_CONTENT, contentProps);
NodeRef acpNodeRef = assocRef.getChildRef();
// apply the titled aspect to behave in the web client
Map<QName, Serializable> titledProps = new HashMap<QName, Serializable>(3, 1.0f);
titledProps.put(ContentModel.PROP_TITLE, this.fileName);
titledProps.put(ContentModel.PROP_DESCRIPTION, Application.getMessage(context, "import_package_description"));
this.nodeService.addAspect(acpNodeRef, ContentModel.ASPECT_TITLED, titledProps);
// add the content to the node
ContentWriter writer = this.contentService.getWriter(acpNodeRef, ContentModel.PROP_CONTENT, true);
writer.setEncoding(this.encoding);
writer.setMimetype(MimetypeMap.MIMETYPE_ACP);
writer.putContent(this.file);
return acpNodeRef;
}
}

View File

@@ -0,0 +1,565 @@
/*
* 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.web.bean;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import javax.faces.validator.ValidatorException;
import javax.portlet.PortletRequest;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.config.ConfigService;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.webdav.WebDAVServlet;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
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.AuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.AuthenticationHelper;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.config.ClientConfigElement;
import org.alfresco.web.ui.common.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* JSF Managed Bean. Backs the "login.jsp" view to provide the form fields used
* to enter user data for login. Also contains bean methods to validate form
* fields and action event fired in response to the Login button being pressed.
*
* @author Kevin Roast
*/
public class LoginBean
{
// ------------------------------------------------------------------------------
// Managed bean properties
/**
* @param authenticationService The AuthenticationService to set.
*/
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
/**
* @param personService The personService to set.
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
/**
* @param nodeService The nodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param browseBean The BrowseBean to set.
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
/**
* @param navigator The NavigationBean to set.
*/
public void setNavigator(NavigationBean navigator)
{
this.navigator = navigator;
}
/**
* @param configService The ConfigService to set.
*/
public void setConfigService(ConfigService configService)
{
this.configService = configService;
}
/**
* @param fileFolderService The FileFolderService to set.
*/
public void setFileFolderService(FileFolderService fileFolderService)
{
this.fileFolderService = fileFolderService;
}
/**
* @param val Username from login dialog
*/
public void setUsername(String val)
{
this.username = val;
}
/**
* @return The username string from login dialog
*/
public String getUsername()
{
return this.username;
}
/**
* @param val Password from login dialog
*/
public void setPassword(String val)
{
this.password = val;
}
/**
* @return The password string from login dialog
*/
public String getPassword()
{
return this.password;
}
/**
* @return the available languages
*/
public SelectItem[] getLanguages()
{
ClientConfigElement config = (ClientConfigElement) this.configService.getGlobalConfig()
.getConfigElement(ClientConfigElement.CONFIG_ELEMENT_ID);
List<String> languages = config.getLanguages();
SelectItem[] items = new SelectItem[languages.size()];
int count = 0;
for (String locale : languages)
{
// get label associated to the locale
String label = config.getLabelForLanguage(locale);
// set default selection
if (count == 0 && this.language == null)
{
// first try to get the language that the current user is using
Locale lastLocale = Application.getLanguage(FacesContext.getCurrentInstance());
if (lastLocale != null)
{
this.language = lastLocale.toString();
}
// else we default to the first item in the list
else
{
this.language = locale;
}
}
items[count++] = new SelectItem(locale, label);
}
return items;
}
/**
* @return Returns the language selection.
*/
public String getLanguage()
{
return this.language;
}
/**
* @param language The language selection to set.
*/
public void setLanguage(String language)
{
this.language = language;
Application.setLanguage(FacesContext.getCurrentInstance(), this.language);
}
// ------------------------------------------------------------------------------
// Validator methods
/**
* Validate password field data is acceptable
*/
public void validatePassword(FacesContext context, UIComponent component, Object value)
throws ValidatorException
{
String pass = (String) value;
if (pass.length() < 3 || pass.length() > 32)
{
String err = MessageFormat.format(Application.getMessage(context, MSG_PASSWORD_LENGTH),
new Object[]{3, 32});
throw new ValidatorException(new FacesMessage(err));
}
}
/**
* Validate Username field data is acceptable
*/
public void validateUsername(FacesContext context, UIComponent component, Object value)
throws ValidatorException
{
String pass = (String) value;
if (pass.length() < 3 || pass.length() > 32)
{
String err = MessageFormat.format(Application.getMessage(context, MSG_USERNAME_LENGTH),
new Object[]{3, 32});
throw new ValidatorException(new FacesMessage(err));
}
}
// ------------------------------------------------------------------------------
// Action event methods
/**
* Login action handler
*
* @return outcome view name
*/
public String login()
{
String outcome = null;
FacesContext fc = FacesContext.getCurrentInstance();
if (this.username != null && this.password != null)
{
// Authenticate via the authentication service, then save the details of user in an object
// in the session - this is used by the servlet filter etc. on each page to check for login
try
{
this.authenticationService.authenticate(this.username, this.password.toCharArray());
// setup User object and Home space ID
User user = new User(this.authenticationService.getCurrentUserName(), this.authenticationService.getCurrentTicket(),
personService.getPerson(this.username));
NodeRef homeSpaceRef = (NodeRef) this.nodeService.getProperty(personService.getPerson(this.username), ContentModel.PROP_HOMEFOLDER);
// check that the home space node exists - else user cannot login
if (this.nodeService.exists(homeSpaceRef) == false)
{
throw new InvalidNodeRefException(homeSpaceRef);
}
user.setHomeSpaceId(homeSpaceRef.getId());
// put the User object in the Session - the authentication servlet will then allow
// the app to continue without redirecting to the login page
Map session = fc.getExternalContext().getSessionMap();
session.put(AuthenticationHelper.AUTHENTICATION_USER, user);
// if an external outcome has been provided then use that, else use default
String externalOutcome = (String)fc.getExternalContext().getSessionMap().get(LOGIN_OUTCOME_KEY);
if (externalOutcome != null)
{
// TODO: This is a quick solution. It would be better to specify the (identifier?)
// of a handler class that would be responsible for processing specific outcome arguments.
if (logger.isDebugEnabled())
logger.debug("External outcome found: " + externalOutcome);
// setup is required for certain outcome requests
if (OUTCOME_DOCDETAILS.equals(externalOutcome))
{
NodeRef nodeRef = null;
String[] args = (String[]) fc.getExternalContext().getSessionMap().get(LOGIN_OUTCOME_ARGS);
if (args[0].equals(WebDAVServlet.WEBDAV_PREFIX))
{
nodeRef = resolveWebDAVPath(fc, args);
}
else if (args.length == 3)
{
StoreRef storeRef = new StoreRef(args[0], args[1]);
nodeRef = new NodeRef(storeRef, args[2]);
}
if (nodeRef != null)
{
// setup the Document on the browse bean
// TODO: the browse bean should accept a full NodeRef - not just an ID
this.browseBean.setupContentAction(nodeRef.getId(), true);
}
}
else if (OUTCOME_SPACEDETAILS.equals(externalOutcome))
{
NodeRef nodeRef = null;
String[] args = (String[]) fc.getExternalContext().getSessionMap().get(LOGIN_OUTCOME_ARGS);
if (args[0].equals(WebDAVServlet.WEBDAV_PREFIX))
{
nodeRef = resolveWebDAVPath(fc, args);
}
else if (args.length == 3)
{
StoreRef storeRef = new StoreRef(args[0], args[1]);
nodeRef = new NodeRef(storeRef, args[2]);
}
if (nodeRef != null)
{
// setup the Space on the browse bean
// TODO: the browse bean should accept a full NodeRef - not just an ID
this.browseBean.setupSpaceAction(nodeRef.getId(), true);
}
}
else if (OUTCOME_BROWSE.equals(externalOutcome))
{
String[] args = (String[]) fc.getExternalContext().getSessionMap().get(LOGIN_OUTCOME_ARGS);
if (args != null)
{
NodeRef nodeRef = null;
int offset = 0;
if (args.length >= 3)
{
offset = args.length - 3;
StoreRef storeRef = new StoreRef(args[0+offset], args[1+offset]);
nodeRef = new NodeRef(storeRef, args[2+offset]);
// setup the ref as current Id in the global navigation bean
this.navigator.setCurrentNodeId(nodeRef.getId());
// check for view mode first argument
if (args[0].equals(LOGIN_ARG_TEMPLATE))
{
this.browseBean.setDashboardView(true);
// the above call will auto-navigate to the correct outcome - so we don't!
externalOutcome = null;
}
}
}
}
fc.getExternalContext().getSessionMap().remove(LOGIN_OUTCOME_KEY);
return externalOutcome;
}
else
{
// if a redirect URL has been provided then use that
String redirectURL = (String)fc.getExternalContext().getSessionMap().get(LOGIN_REDIRECT_KEY);
if (redirectURL != null)
{
if (logger.isDebugEnabled())
logger.debug("Redirect URL found: " + redirectURL);
// remove URL from session
fc.getExternalContext().getSessionMap().remove(LOGIN_REDIRECT_KEY);
try
{
fc.getExternalContext().redirect(redirectURL);
fc.responseComplete();
return null;
}
catch (IOException ioErr)
{
logger.warn("Unable to redirect to url: " + redirectURL);
}
}
else
{
return "success";
}
}
}
catch (AuthenticationException aerr)
{
Utils.addErrorMessage(Application.getMessage(fc, MSG_ERROR_UNKNOWN_USER));
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(fc,
Repository.ERROR_NOHOME), refErr.getNodeRef().getId()));
}
}
else
{
Utils.addErrorMessage(Application.getMessage(fc, MSG_ERROR_MISSING));
}
return outcome;
}
/**
* Invalidate ticket and logout user
*/
public String logout()
{
FacesContext context = FacesContext.getCurrentInstance();
Map session = context.getExternalContext().getSessionMap();
User user = (User) session.get(AuthenticationHelper.AUTHENTICATION_USER);
boolean alfrescoAuth = (session.get(LOGIN_EXTERNAL_AUTH) == null);
// invalidate Session for this user
if (Application.inPortalServer() == false)
{
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
request.getSession().invalidate();
}
else
{
PortletRequest request = (PortletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
request.getPortletSession().invalidate();
}
// invalidate User ticket
if (user != null)
{
this.authenticationService.invalidateTicket(user.getTicket());
}
// set language to last used
if (this.language != null && this.language.length() != 0)
{
Application.setLanguage(context, this.language);
}
return alfrescoAuth ? "logout" : "relogin";
}
// ------------------------------------------------------------------------------
// Private helpers
/**
* Resolves the given path elements to a NodeRef in the current repository
*
* @param context Faces context
* @param args The elements of the path to lookup
*/
private NodeRef resolveWebDAVPath(FacesContext context, String[] args)
{
NodeRef nodeRef = null;
List<String> paths = new ArrayList<String>(args.length-1);
FileInfo file = null;
try
{
// create a list of path elements (decode the URL as we go)
for (int x = 1; x < args.length; x++)
{
paths.add(URLDecoder.decode(args[x], "UTF-8"));
}
if (logger.isDebugEnabled())
logger.debug("Attempting to resolve webdav path to NodeRef: " + paths);
// get the company home node to start the search from
NodeRef companyHome = new NodeRef(Repository.getStoreRef(),
Application.getCompanyRootId());
file = this.fileFolderService.resolveNamePath(companyHome, paths);
nodeRef = file.getNodeRef();
}
catch (UnsupportedEncodingException uee)
{
if (logger.isWarnEnabled())
logger.warn("Failed to resolve webdav path", uee);
nodeRef = null;
}
catch (FileNotFoundException fne)
{
if (logger.isWarnEnabled())
logger.debug("Failed to resolve webdav path", fne);
nodeRef = null;
}
return nodeRef;
}
// ------------------------------------------------------------------------------
// Private data
private static final Log logger = LogFactory.getLog(LoginBean.class);
/** I18N messages */
private static final String MSG_ERROR_MISSING = "error_login_missing";
private static final String MSG_ERROR_UNKNOWN_USER = "error_login_user";
private static final String MSG_USERNAME_CHARS = "login_err_username_chars";
private static final String MSG_USERNAME_LENGTH = "login_err_username_length";
private static final String MSG_PASSWORD_CHARS = "login_err_password_chars";
private static final String MSG_PASSWORD_LENGTH = "login_err_password_length";
public static final String LOGIN_REDIRECT_KEY = "_alfRedirect";
public static final String LOGIN_OUTCOME_KEY = "_alfOutcome";
public static final String LOGIN_OUTCOME_ARGS = "_alfOutcomeArgs";
public static final String LOGIN_EXTERNAL_AUTH= "_alfExternalAuth";
public final static String OUTCOME_DOCDETAILS = "showDocDetails";
public final static String OUTCOME_SPACEDETAILS = "showSpaceDetails";
public final static String OUTCOME_BROWSE = "browse";
private static final String LOGIN_ARG_TEMPLATE = "template";
/** user name */
private String username = null;
/** password */
private String password = null;
/** language locale selection */
private String language = null;
/** PersonService bean reference */
private PersonService personService;
/** AuthenticationService bean reference */
private AuthenticationService authenticationService;
/** NodeService bean reference */
private NodeService nodeService;
/** The BrowseBean reference */
private BrowseBean browseBean;
/** The NavigationBean bean reference */
private NavigationBean navigator;
/** ConfigService bean reference */
private ConfigService configService;
/** FileFolderService bean reference */
private FileFolderService fileFolderService;
}

View File

@@ -0,0 +1,674 @@
/*
* 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.web.bean;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.alfresco.config.ConfigService;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.filesys.CIFSServer;
import org.alfresco.filesys.server.filesys.DiskSharedDevice;
import org.alfresco.filesys.smb.server.repo.ContentContext;
import org.alfresco.filesys.smb.server.repo.ContentDiskInterface;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.bean.wizard.NewSpaceWizard;
import org.alfresco.web.config.ClientConfigElement;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.IBreadcrumbHandler;
import org.alfresco.web.ui.common.component.UIBreadcrumb;
import org.alfresco.web.ui.common.component.UIModeList;
import org.alfresco.web.ui.repo.component.IRepoBreadcrumbHandler;
import org.alfresco.web.ui.repo.component.shelf.UIShelf;
import org.apache.log4j.Logger;
/**
* @author Kevin Roast
*/
public class NavigationBean
{
// ------------------------------------------------------------------------------
// Bean property getters and setters
/**
* @param nodeService The nodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param searchService The searchService to set.
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @param namespaceService The namespaceService to set.
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param cifsServer The cifsServer to set.
*/
public void setCifsServer(CIFSServer cifsServer)
{
this.cifsServer = cifsServer;
}
/**
* @param contentDiskDriver The contentDiskDriver to set.
*/
public void setContentDiskDriver(ContentDiskInterface contentDiskDriver)
{
this.contentDiskDriver = contentDiskDriver;
}
/**
* @param configService The ConfigService to set.
*/
public void setConfigService(ConfigService configService)
{
this.configService = configService;
}
/**
* @return the User object representing the current instance for this user
*/
public User getCurrentUser()
{
return Application.getCurrentUser(FacesContext.getCurrentInstance());
}
/**
* Return the expanded state of the Shelf panel wrapper component
*
* @return the expanded state of the Shelf panel wrapper component
*/
public boolean isShelfExpanded()
{
return this.shelfExpanded;
}
/**
* Set the expanded state of the Shelf panel wrapper component
*
* @param expanded true to expanded the Shelf panel area, false to hide it
*/
public void setShelfExpanded(boolean expanded)
{
this.shelfExpanded = expanded;
}
/**
* @return Returns the array containing the expanded state of the shelf items
*/
public boolean[] getShelfItemExpanded()
{
return this.shelfItemExpanded;
}
/**
* @param shelfItemExpanded The array containing the expanded state of the shelf items
*/
public void setShelfItemExpanded(boolean[] shelfItemExpanded)
{
this.shelfItemExpanded = shelfItemExpanded;
}
/**
* @return Returns the toolbar Location.
*/
public String getToolbarLocation()
{
return this.toolbarLocation;
}
/**
* @param toolbarLocation The toolbar Location to set.
*/
public void setToolbarLocation(String toolbarLocation)
{
this.toolbarLocation = toolbarLocation;
}
/**
* @return Returns the helpUrl.
*/
public String getHelpUrl()
{
if (this.clientConfig == null)
{
initFromClientConfig();
}
return this.helpUrl;
}
/**
* @param helpUrl The helpUrl to set.
*/
public void setHelpUrl(String helpUrl)
{
this.helpUrl = helpUrl;
}
/**
* @return Returns the search context object if any.
*/
public SearchContext getSearchContext()
{
return this.searchContext;
}
/**
* @param searchContext The search context object to set or null to clear search.
*/
public void setSearchContext(SearchContext searchContext)
{
this.searchContext = searchContext;
UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
}
/**
* @return Returns the currently browsing node Id.
*/
public String getCurrentNodeId()
{
return this.currentNodeId;
}
/**
* Set the node Id of the current folder/space container node.
* <p>
* Setting this value causes the UI to update and display the specified node as current.
*
* @param currentNodeId The currently browsing node Id.
*/
public void setCurrentNodeId(String currentNodeId)
{
if (s_logger.isDebugEnabled())
s_logger.debug("Setting current node id to: " + currentNodeId);
if (currentNodeId == null)
{
throw new AlfrescoRuntimeException("Can not set the current node id to null");
}
// set the current Node Id for our UI context operations
this.currentNodeId = currentNodeId;
// clear other context that is based on or relevant to the Node id
this.currentNode = null;
this.searchContext = null;
// inform any interested beans that the UI needs updating after this change
UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
// clear current node context after the notify - this is to ensure that if any delegates
// performed operations on the current node, that we have fresh data for the next View
this.currentNode = null;
}
/**
* @return true if the current node has a template view available
*/
public boolean getCurrentNodeHasTemplate()
{
boolean templateView = false;
Node node = getCurrentNode();
if (node.hasAspect(ContentModel.ASPECT_TEMPLATABLE))
{
NodeRef templateRef = (NodeRef)node.getProperties().get(ContentModel.PROP_TEMPLATE);
templateView = (templateRef != null && this.nodeService.exists(templateRef));
}
return templateView;
}
/**
* @return the NodeRef.toString() for the current node template view if it has one set
*/
public String getCurrentNodeTemplate()
{
String strRef = null;
if (getCurrentNodeHasTemplate() == true)
{
strRef = getCurrentNode().getProperties().get(ContentModel.PROP_TEMPLATE).toString();
}
return strRef;
}
/**
* Returns a model for use by a template on a space Dashboard page.
*
* @return model containing current current space info.
*/
public Map getTemplateModel()
{
HashMap model = new HashMap(1, 1.0f);
FacesContext fc = FacesContext.getCurrentInstance();
TemplateNode spaceNode = new TemplateNode(getCurrentNode().getNodeRef(), Repository.getServiceRegistry(fc),
new TemplateImageResolver() {
public String resolveImagePathForName(String filename, boolean small) {
return Utils.getFileTypeImage(filename, small);
}
});
model.put("space", spaceNode);
return model;
}
/**
* Clear state so that the current node properties cache for the next time they are requested
*/
public void resetCurrentNodeProperties()
{
this.currentNode = null;
}
/**
* @return The Map of properties for the current Node.
*/
public Map<String, Object> getNodeProperties()
{
return getCurrentNode().getProperties();
}
/**
* @return The current Node object for UI context operations
*/
public Node getCurrentNode()
{
if (this.currentNode == null)
{
if (this.currentNodeId == null)
{
throw new AlfrescoRuntimeException("Cannot retrieve current Node if NodeId is null!");
}
if (s_logger.isDebugEnabled())
s_logger.debug("Caching properties for node id: " + this.currentNodeId);
NodeRef nodeRef;
Node node;
Map<String, Object> props;
try
{
// build a node which components on the JSP page can bind too
nodeRef = new NodeRef(Repository.getStoreRef(), this.currentNodeId);
node = new Node(nodeRef);
// early init properties for this node (by getProperties() call)
// resolve icon in-case one has not been set
props = node.getProperties();
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), ERROR_DELETED_FOLDER), new Object[] {this.currentNodeId}) );
nodeRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
node = new Node(nodeRef);
props = node.getProperties();
}
String icon = (String)props.get("app:icon");
props.put("icon", icon != null ? icon : NewSpaceWizard.SPACE_ICON_DEFAULT);
Path path = this.nodeService.getPath(nodeRef);
// resolve CIFS network folder location for this node
DiskSharedDevice diskShare = cifsServer.getConfiguration().getPrimaryFilesystem();
if (diskShare != null)
{
ContentContext contentCtx = (ContentContext) diskShare.getContext();
NodeRef rootNode = contentCtx.getRootNode();
String cifsPath = Repository.getNamePath(this.nodeService, path, rootNode, "\\", "file:///" + getCIFSServerPath(diskShare));
node.getProperties().put("cifsPath", cifsPath);
node.getProperties().put("cifsPathLabel", cifsPath.substring(8)); // strip file:/// part
}
this.currentNode = node;
}
return this.currentNode;
}
/**
* @return Returns the breadcrumb handler elements representing the location path of the UI.
*/
public List<IBreadcrumbHandler> getLocation()
{
if (this.location == null)
{
// init the location from the User object for the first time
User user = Application.getCurrentUser(FacesContext.getCurrentInstance());
NodeRef homeSpaceRef = new NodeRef(Repository.getStoreRef(), user.getHomeSpaceId());
String homeSpaceName = Repository.getNameForNode(this.nodeService, homeSpaceRef);
// set the current node to the users Home Space Id
setCurrentNodeId(user.getHomeSpaceId());
// setup the breadcrumb with the same location
List<IBreadcrumbHandler> elements = new ArrayList<IBreadcrumbHandler>(1);
elements.add(new NavigationBreadcrumbHandler(homeSpaceRef, homeSpaceName));
setLocation(elements);
}
return this.location;
}
/**
* @param location The UI location representation to set.
*/
public void setLocation(List<IBreadcrumbHandler> location)
{
this.location = location;
}
/**
* Sets up the dispatch context so that the navigation handler knows
* what object is being acted upon
*
* @param node The node to be added to the dispatch context
*/
public void setupDispatchContext(Node node)
{
this.dispatchContext = node;
}
/**
* Resets the dispatch context
*/
public void resetDispatchContext()
{
this.dispatchContext = null;
}
/**
* Returns the node currently set in the dispatch context
*
* @return The node being dispatched or null if there is no
* dispatch context
*/
public Node getDispatchContextNode()
{
return this.dispatchContext;
}
// ------------------------------------------------------------------------------
// Navigation action event handlers
/**
* Action handler to toggle the expanded state of the shelf.
* The panel component wrapping the shelf area of the UI is value bound to the shelfExpanded property.
*/
public void toggleShelf(ActionEvent event)
{
this.shelfExpanded = !this.shelfExpanded;
}
/**
* Action handler called after a Shelf Group has had its expanded state toggled by the user
*/
public void shelfGroupToggled(ActionEvent event)
{
UIShelf.ShelfEvent shelfEvent = (UIShelf.ShelfEvent)event;
this.shelfItemExpanded[shelfEvent.Index] = shelfEvent.Expanded;
}
/**
* Action to change the toolbar location
* Currently this will changed the location from Company to the users Home space
*/
public void toolbarLocationChanged(ActionEvent event)
{
FacesContext context = FacesContext.getCurrentInstance();
try
{
UIModeList locationList = (UIModeList)event.getComponent();
String location = locationList.getValue().toString();
setToolbarLocation(location);
if (LOCATION_COMPANY.equals(location))
{
List<IBreadcrumbHandler> elements = new ArrayList<IBreadcrumbHandler>(1);
NodeRef companyRootRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
String companySpaceName = Repository.getNameForNode(this.nodeService, companyRootRef);
elements.add(new NavigationBreadcrumbHandler(companyRootRef, companySpaceName));
setLocation(elements);
setCurrentNodeId(companyRootRef.getId());
}
else if (LOCATION_HOME.equals(location))
{
List<IBreadcrumbHandler> elements = new ArrayList<IBreadcrumbHandler>(1);
String homeSpaceId = Application.getCurrentUser(context).getHomeSpaceId();
NodeRef homeSpaceRef = new NodeRef(Repository.getStoreRef(), homeSpaceId);
String homeSpaceName = Repository.getNameForNode(this.nodeService, homeSpaceRef);
elements.add(new NavigationBreadcrumbHandler(homeSpaceRef, homeSpaceName));
setLocation(elements);
setCurrentNodeId(homeSpaceRef.getId());
}
// we need to force a navigation to refresh the browse screen breadcrumb
context.getApplication().getNavigationHandler().handleNavigation(context, null, "browse");
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_NOHOME), Application.getCurrentUser(context).getHomeSpaceId()), refErr );
}
catch (Exception err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
}
}
/**
* @param diskShare Filesystem shared device
* @return CIFS server path as network style string label
*/
public String getCIFSServerPath(DiskSharedDevice diskShare)
{
if (this.cifsServerPath == null)
{
StringBuilder buf = new StringBuilder(24);
String serverName = this.cifsServer.getConfiguration().getServerName();
if (serverName != null && serverName.length() != 0)
{
buf.append("\\\\")
.append(serverName)
.append("\\");
buf.append(diskShare.getName());
}
this.cifsServerPath = buf.toString();
}
return this.cifsServerPath;
}
// ------------------------------------------------------------------------------
// Private helpers
/**
* Initialise default values from client configuration
*/
private void initFromClientConfig()
{
this.clientConfig = (ClientConfigElement)this.configService.getGlobalConfig().getConfigElement(
ClientConfigElement.CONFIG_ELEMENT_ID);
this.helpUrl = clientConfig.getHelpUrl();
}
// ------------------------------------------------------------------------------
// Inner classes
/**
* Class to handle breadcrumb interaction for top-level navigation pages
*/
public class NavigationBreadcrumbHandler implements IRepoBreadcrumbHandler
{
private static final long serialVersionUID = 4833194653193016638L;
/**
* Constructor
*
* @param label Element label
*/
public NavigationBreadcrumbHandler(NodeRef ref, String label)
{
this.label = label;
this.ref = ref;
}
/**
* @see java.lang.Object#toString()
*/
public String toString()
{
return this.label;
}
/**
* @see org.alfresco.web.ui.common.component.IBreadcrumbHandler#navigationOutcome(org.alfresco.web.ui.common.component.UIBreadcrumb)
*/
public String navigationOutcome(UIBreadcrumb breadcrumb)
{
// set the current node to the specified top level node ID
FacesContext fc = FacesContext.getCurrentInstance();
setCurrentNodeId(ref.getId());
setLocation( (List)breadcrumb.getValue() );
// setup the dispatch context
setupDispatchContext(new Node(ref));
if (fc.getViewRoot().getViewId().equals(BrowseBean.BROWSE_VIEW_ID))
{
return null;
}
else
{
return "browse";
}
}
public NodeRef getNodeRef()
{
return this.ref;
}
private String label;
private NodeRef ref;
}
// ------------------------------------------------------------------------------
// Private data
private static Logger s_logger = Logger.getLogger(NavigationBean.class);
/** constant values used by the toolbar location modelist control */
private static final String LOCATION_COMPANY = "company";
private static final String LOCATION_HOME = "home";
private static final String ERROR_DELETED_FOLDER = "error_deleted_folder";
/** The NodeService to be used by the bean */
private NodeService nodeService;
/** The SearchService to be used by the bean */
private SearchService searchService;
/** NamespaceService bean reference */
private NamespaceService namespaceService;
/** CIFSServer bean reference */
private CIFSServer cifsServer;
/** CIFS content disk driver bean reference */
private ContentDiskInterface contentDiskDriver;
/** ConfigService bean reference */
private ConfigService configService;
/** Client configuration object */
private ClientConfigElement clientConfig = null;
/** Cached path to our CIFS server and top level node DIR */
private String cifsServerPath;
/** Node Id we are using for UI context operations */
private String currentNodeId;
/** Node we are using for UI context operations */
private Node currentNode = null;
/** Node we are using for dispatching */
private Node dispatchContext = null;
/** Current toolbar location */
private String toolbarLocation = LOCATION_HOME;
/** Search context object we are currently using or null for no search */
private SearchContext searchContext;
/** expanded state of the Shelf panel wrapper component */
private boolean shelfExpanded = true;
/** expanded state of the Shelf item components */
private boolean[] shelfItemExpanded = new boolean[] {true, true, true, false, false};
/** list of the breadcrumb handler elements representing the location path of the UI */
private List<IBreadcrumbHandler> location = null;
/** The client Help file url */
private String helpUrl;
}

View File

@@ -0,0 +1,204 @@
/*
* 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.web.bean;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.alfresco.config.ConfigService;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.IContextListener;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.config.ClientConfigElement;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.repo.component.shelf.UIRecentSpacesShelfItem;
import org.apache.log4j.Logger;
/**
* This bean manages the real-time updated list of Recent Spaces in the Shelf component.
* <p>
* Registers itself as a UI Context Listener so it is informed as to when the current Node ID
* has changed in the NavigationBeans. This is used to keep the list of spaces up-to-date.
*
* @author Kevin Roast
*/
public class RecentSpacesBean implements IContextListener
{
private static Logger logger = Logger.getLogger(RecentSpacesBean.class);
/** The NavigationBean reference */
private NavigationBean navigator;
/** The BrowseBean reference */
private BrowseBean browseBean;
/** ConfigService bean reference */
private ConfigService configService;
/** Maximum number of recent spaces to show */
private Integer maxRecentSpaces = null;
/** List of recent space nodes */
private List<Node> recentSpaces = new LinkedList<Node>();
// ------------------------------------------------------------------------------
// Construction
/**
* Default Constructor
*/
public RecentSpacesBean()
{
UIContextService.getInstance(FacesContext.getCurrentInstance()).registerBean(this);
}
// ------------------------------------------------------------------------------
// Bean property getters and setters
/**
* @param navigator The NavigationBean to set.
*/
public void setNavigator(NavigationBean navigator)
{
this.navigator = navigator;
}
/**
* @param browseBean The BrowseBean to set.
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
/**
* @param configService The ConfigService to set.
*/
public void setConfigService(ConfigService configService)
{
this.configService = configService;
}
/**
* @return the List of recent spaces
*/
public List<Node> getRecentSpaces()
{
return this.recentSpaces;
}
/**
* @param spaces List of Nodes
*/
public void setRecentSpaces(List<Node> spaces)
{
this.recentSpaces = spaces;
}
// ------------------------------------------------------------------------------
// Action method handlers
/**
* Action handler bound to the recent spaces Shelf component called when a Space is clicked
*/
public void navigate(ActionEvent event)
{
// work out which node was clicked from the event data
UIRecentSpacesShelfItem.RecentSpacesEvent spaceEvent = (UIRecentSpacesShelfItem.RecentSpacesEvent)event;
Node selectedNode = this.recentSpaces.get(spaceEvent.Index);
NodeRef nodeRef = selectedNode.getNodeRef();
try
{
// then navigate to the appropriate node in UI
// use browse bean functionality for this as it will update the breadcrumb for us
this.browseBean.updateUILocation(nodeRef);
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {nodeRef.getId()}) );
// remove invalid node from recent spaces list
this.recentSpaces.remove(spaceEvent.Index);
}
}
// ------------------------------------------------------------------------------
// IContextListener implementation
/**
* @see org.alfresco.web.app.context.IContextListener#contextUpdated()
*/
public void contextUpdated()
{
// We use this listener handler to refresh the recent spaces list. At the point
// where this method is called, the current node Id in UI will probably have changed.
Node node = this.navigator.getCurrentNode();
// search for this node - if it's already in the list remove it so
// that it appears at the top for us
for (int i=0; i<this.recentSpaces.size(); i++)
{
if (node.getId().equals(this.recentSpaces.get(i).getId()))
{
// found same node already in the list - remove it
this.recentSpaces.remove(i);
break;
}
}
// remove an item if the list is at the maximum length
int maxItems = getMaxRecentSpaces();
if (this.recentSpaces.size() == maxItems)
{
this.recentSpaces.remove(maxItems - 1);
}
if (logger.isDebugEnabled())
logger.debug("Inserting node: " + node.getName() + " at top of recent spaces list.");
// insert our Node at the top of the list so it's most relevent
this.recentSpaces.add(0, node);
}
/**
* @return the max number of recent spaces to show, retrieved from client config
*/
private int getMaxRecentSpaces()
{
if (maxRecentSpaces == null)
{
ClientConfigElement config = (ClientConfigElement)this.configService.getGlobalConfig().getConfigElement(
ClientConfigElement.CONFIG_ELEMENT_ID);
maxRecentSpaces = Integer.valueOf(config.getRecentSpacesItems());
}
return maxRecentSpaces.intValue();
}
}

View File

@@ -0,0 +1,327 @@
/*
* 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.web.bean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionCondition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.rule.Rule;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.UIModeList;
import org.alfresco.web.ui.common.component.data.UIRichList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Backing bean for the manage content rules dialog
*
* @author gavinc
*/
public class RulesBean
{
private static final String MSG_ERROR_DELETE_RULE = "error_delete_rule";
private static final String LOCAL = "local";
private static final String INHERITED = "inherited";
private static Log logger = LogFactory.getLog(RulesBean.class);
private String viewMode = INHERITED;
private BrowseBean browseBean;
private RuleService ruleService;
private List<WrappedRule> rules;
private Rule currentRule;
private UIRichList richList;
/**
* Returns the current view mode the list of rules is in
*
* @return The current view mode
*/
public String getViewMode()
{
return this.viewMode;
}
/**
* @return The space to work against
*/
public Node getSpace()
{
return this.browseBean.getActionSpace();
}
/**
* Returns the list of rules to display
*
* @return
*/
public List<WrappedRule> getRules()
{
boolean includeInherited = true;
if (this.viewMode.equals(LOCAL))
{
includeInherited = false;
}
// get the rules from the repository
List<Rule> repoRules = this.ruleService.getRules(getSpace().getNodeRef(), includeInherited);
this.rules = new ArrayList<WrappedRule>(repoRules.size());
// wrap them all passing the current space
for (Rule rule : repoRules)
{
WrappedRule wrapped = new WrappedRule(rule, getSpace().getNodeRef());
this.rules.add(wrapped);
}
return this.rules;
}
/**
* Handles a rule being clicked ready for an action i.e. edit or delete
*
* @param event The event representing the click
*/
public void setupRuleAction(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
if (logger.isDebugEnabled())
logger.debug("Rule clicked, it's id is: " + id);
this.currentRule = this.ruleService.getRule(
getSpace().getNodeRef(), id);
}
}
/**
* Returns the current rule
*
* @return The current rule
*/
public Rule getCurrentRule()
{
return this.currentRule;
}
/**
* Handler called upon the completion of the Delete Rule page
*
* @return outcome
*/
public String deleteOK()
{
String outcome = null;
if (this.currentRule != null)
{
try
{
String ruleTitle = this.currentRule.getTitle();
this.ruleService.removeRule(getSpace().getNodeRef(),
this.currentRule);
// clear the current rule
this.currentRule = null;
// setting the outcome will show the browse view again
outcome = "manageRules";
if (logger.isDebugEnabled())
logger.debug("Deleted rule '" + ruleTitle + "'");
}
catch (Throwable err)
{
Utils.addErrorMessage(Application.getMessage(
FacesContext.getCurrentInstance(), MSG_ERROR_DELETE_RULE) + err.getMessage(), err);
}
}
else
{
logger.warn("WARNING: deleteOK called without a current Rule!");
}
return outcome;
}
/**
* Change the current view mode based on user selection
*
* @param event ActionEvent
*/
public void viewModeChanged(ActionEvent event)
{
UIModeList viewList = (UIModeList)event.getComponent();
this.viewMode = viewList.getValue().toString();
// force the list to be re-queried when the page is refreshed
if (this.richList != null)
{
this.richList.setValue(null);
}
}
/**
* Sets the UIRichList component being used by this backing bean
*
* @param richList UIRichList component
*/
public void setRichList(UIRichList richList)
{
this.richList = richList;
this.richList.setValue(null);
}
/**
* Returns the UIRichList component being used by this backing bean
*
* @return UIRichList component
*/
public UIRichList getRichList()
{
return this.richList;
}
/**
* @param browseBean The BrowseBean to set.
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
/**
* @param ruleService Sets the rule service to use
*/
public void setRuleService(RuleService ruleService)
{
this.ruleService = ruleService;
}
/**
* Inner class to wrap the Rule objects so we can expose a flag to indicate whether
* the rule is a local or inherited rule
*/
public class WrappedRule
{
private Rule rule;
private NodeRef ruleNode;
/**
* Constructs a RuleWrapper object
*
* @param rule The rule we are wrapping
* @param ruleNode The node the rules belong to
*/
public WrappedRule(Rule rule, NodeRef ruleNode)
{
this.rule = rule;
this.ruleNode = ruleNode;
}
/**
* Returns the rule being wrapped
*
* @return The wrapped Rule
*/
public Rule getRule()
{
return this.rule;
}
/**
* Determines whether the current rule is a local rule or
* has been inherited from a parent
*
* @return true if the rule is defined on the current node
*/
public boolean getLocal()
{
return ruleNode.equals(this.rule.getOwningNodeRef());
}
/** Methods to support sorting of the rules list in a table */
/**
* Returns the rule id
*
* @return The id
*/
public String getId()
{
return this.rule.getId();
}
/**
* Returns the rule title
*
* @return The title
*/
public String getTitle()
{
return this.rule.getTitle();
}
/**
* Returns the rule description
*
* @return The description
*/
public String getDescription()
{
return this.rule.getDescription();
}
/**
* Returns the created date
*
* @return The created date
*/
public Date getCreatedDate()
{
return this.rule.getCreatedDate();
}
/**
* Returns the modfified date
*
* @return The modified date
*/
public Date getModifiedDate()
{
return this.rule.getModifiedDate();
}
}
}

View File

@@ -0,0 +1,542 @@
/*
* 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.web.bean;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.faces.context.FacesContext;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.search.ISO9075;
import org.alfresco.repo.search.impl.lucene.QueryParser;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.bean.repository.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Holds the context required to build a search query and can return the populated query.
*
* @author Kevin Roast
*/
public final class SearchContext implements Serializable
{
/** Search mode constants */
public final static int SEARCH_ALL = 0;
public final static int SEARCH_FILE_NAMES_CONTENTS = 1;
public final static int SEARCH_FILE_NAMES = 2;
public final static int SEARCH_SPACE_NAMES = 3;
/** the search text string */
private String text = "";
/** mode for the search */
private int mode = SearchContext.SEARCH_ALL;
/** folder node location for the search */
private String location = null;
/** categories to add to the search */
private String[] categories = new String[0];
/** true to search location children as well as location */
private boolean locationChildren = true;
/** true to search category children as well as category */
private boolean categoryChildren = true;
/** content type to restrict search against */
private String contentType = null;
/** content mimetype to restrict search against */
private String mimeType = null;
/** any extra query attributes to add to the search */
private Map<QName, String> queryAttributes = new HashMap<QName, String>(5, 1.0f);
/** any additional range attribute to add to the search */
private Map<QName, RangeProperties> rangeAttributes = new HashMap<QName, RangeProperties>(5, 1.0f);
/** any additional fixed value attributes to add to the search, such as boolean or noderef */
private Map<QName, String> queryFixedValues = new HashMap<QName, String>(5, 1.0f);
/** logger */
private static Log logger = LogFactory.getLog(SearchContext.class);
/**
* Build the search query string based on the current search context members.
*
* @return prepared search query string
*/
public String buildQuery()
{
String query;
// the QName for the well known "name" attribute
String nameAttr = Repository.escapeQName(QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "name"));
// match against content text
String text = this.text.trim();
String fullTextQuery;
String nameAttrQuery;
if (text.indexOf(' ') == -1)
{
// simple single word text search
if (text.charAt(0) != '*')
{
// escape characters and append the wildcard character
String safeText = QueryParser.escape(text);
fullTextQuery = " TEXT:" + safeText + '*';
nameAttrQuery = " @" + nameAttr + ":" + safeText + '*';
}
else
{
// found a leading wildcard - prepend it again after escaping the other characters
String safeText = QueryParser.escape(text.substring(1));
fullTextQuery = " TEXT:*" + safeText + '*';
nameAttrQuery = " @" + nameAttr + ":*" + safeText + '*';
}
}
else
{
// multiple word search
if (text.charAt(0) == '"' && text.charAt(text.length() - 1) == '"')
{
// as quoted phrase
String quotedSafeText = '"' + QueryParser.escape(text.substring(1, text.length() - 1)) + '"';
fullTextQuery = " TEXT:" + quotedSafeText;
nameAttrQuery = " @" + nameAttr + ":" + quotedSafeText;
}
else
{
// as individual search terms
StringTokenizer t = new StringTokenizer(text, " ");
StringBuilder fullTextBuf = new StringBuilder(64);
StringBuilder nameAttrBuf = new StringBuilder(64);
fullTextBuf.append('(');
nameAttrBuf.append('(');
while (t.hasMoreTokens())
{
String term = t.nextToken();
if (term.charAt(0) != '*')
{
String safeTerm = QueryParser.escape(term);
fullTextBuf.append("TEXT:").append(safeTerm).append('*');
nameAttrBuf.append("@").append(nameAttr).append(":").append(safeTerm).append('*');
}
else
{
String safeTerm = QueryParser.escape(term.substring(1));
fullTextBuf.append("TEXT:*").append(safeTerm).append('*');
nameAttrBuf.append("@").append(nameAttr).append(":*").append(safeTerm).append('*');
}
if (t.hasMoreTokens())
{
fullTextBuf.append(" OR ");
nameAttrBuf.append(" OR ");
}
}
fullTextBuf.append(')');
nameAttrBuf.append(')');
fullTextQuery = fullTextBuf.toString();
nameAttrQuery = nameAttrBuf.toString();
}
}
// match a specific PATH for space location or categories
StringBuilder pathQuery = null;
if (location != null || (categories != null && categories.length !=0))
{
pathQuery = new StringBuilder(128);
if (location != null)
{
pathQuery.append(" PATH:\"").append(location).append("\" ");
}
if (categories != null && categories.length != 0)
{
for (int i=0; i<categories.length; i++)
{
if (pathQuery.length() != 0)
{
pathQuery.append("OR");
}
pathQuery.append(" PATH:\"").append(categories[i]).append("\" ");
}
}
}
// match any extra query attribute values specified
StringBuilder attributeQuery = null;
if (queryAttributes.size() != 0)
{
attributeQuery = new StringBuilder(queryAttributes.size() << 6);
for (QName qname : queryAttributes.keySet())
{
String escapedName = Repository.escapeQName(qname);
String value = QueryParser.escape(queryAttributes.get(qname));
attributeQuery.append(" +@").append(escapedName)
.append(":").append(value).append('*');
}
}
// match any extra fixed value attributes specified
if (queryFixedValues.size() != 0)
{
if (attributeQuery == null)
{
attributeQuery = new StringBuilder(queryFixedValues.size() << 6);
}
for (QName qname : queryFixedValues.keySet())
{
String escapedName = Repository.escapeQName(qname);
String value = queryFixedValues.get(qname);
attributeQuery.append(" +@").append(escapedName)
.append(":\"").append(value).append('"');
}
}
// range attributes are a special case also
if (rangeAttributes.size() != 0)
{
if (attributeQuery == null)
{
attributeQuery = new StringBuilder(rangeAttributes.size() << 6);
}
for (QName qname : rangeAttributes.keySet())
{
String escapedName = Repository.escapeQName(qname);
RangeProperties rp = rangeAttributes.get(qname);
String value1 = QueryParser.escape(rp.lower);
String value2 = QueryParser.escape(rp.upper);
attributeQuery.append(" +@").append(escapedName)
.append(":").append(rp.inclusive ? "[" : "{").append(value1)
.append(" TO ").append(value2).append(rp.inclusive ? "]" : "}");
}
}
// mimetype is a special case - it is indexed as a special attribute it comes from the combined
// ContentData attribute of cm:content - ContentData string cannot be searched directly
if (mimeType != null && mimeType.length() != 0)
{
if (attributeQuery == null)
{
attributeQuery = new StringBuilder(64);
}
String escapedName = Repository.escapeQName(QName.createQName(ContentModel.PROP_CONTENT + ".mimetype"));
attributeQuery.append(" +@").append(escapedName)
.append(":").append(mimeType);
}
// match against appropriate content type
String fileTypeQuery;
if (contentType != null)
{
fileTypeQuery = " +TYPE:\"" + contentType + "\" ";
}
else
{
// default to cm:content
fileTypeQuery = " +TYPE:\"{" + NamespaceService.CONTENT_MODEL_1_0_URI + "}content\" ";
}
// match against FOLDER type
String folderTypeQuery = " +TYPE:\"{" + NamespaceService.CONTENT_MODEL_1_0_URI + "}folder\" ";
switch (mode)
{
case SearchContext.SEARCH_ALL:
query = '(' + fileTypeQuery + " AND " + '(' + nameAttrQuery + fullTextQuery + ')' + ')' + " OR " +
'(' + folderTypeQuery + " AND " + nameAttrQuery + ')';
break;
case SearchContext.SEARCH_FILE_NAMES:
query = fileTypeQuery + " AND " + nameAttrQuery;
break;
case SearchContext.SEARCH_FILE_NAMES_CONTENTS:
query = fileTypeQuery + " AND " + '(' + nameAttrQuery + fullTextQuery + ')';
break;
case SearchContext.SEARCH_SPACE_NAMES:
query = folderTypeQuery + " AND " + nameAttrQuery;
break;
default:
throw new IllegalStateException("Unknown search mode specified: " + mode);
}
// match entire query against any additional attributes specified
if (attributeQuery != null)
{
query = attributeQuery + " AND (" + query + ')';
}
// match entire query against specified Space path
if (pathQuery != null)
{
query = pathQuery + " AND (" + query + ')';
}
if (logger.isDebugEnabled())
logger.debug("Query: " + query);
return query;
}
/**
* Generate a search XPATH pointing to the specified node Id, optionally return an XPATH
* that includes the child nodes.
*
* @param id Of the node to generate path too
* @param children Whether to include children of the node
*
* @return the path
*/
/*package*/ static String getPathFromSpaceRef(NodeRef ref, boolean children)
{
FacesContext context = FacesContext.getCurrentInstance();
Path path = Repository.getServiceRegistry(context).getNodeService().getPath(ref);
NamespaceService ns = Repository.getServiceRegistry(context).getNamespaceService();
StringBuilder buf = new StringBuilder(64);
for (int i=0; i<path.size(); i++)
{
String elementString = "";
Path.Element element = path.get(i);
if (element instanceof Path.ChildAssocElement)
{
ChildAssociationRef elementRef = ((Path.ChildAssocElement)element).getRef();
if (elementRef.getParentRef() != null)
{
Collection prefixes = ns.getPrefixes(elementRef.getQName().getNamespaceURI());
if (prefixes.size() >0)
{
elementString = '/' + (String)prefixes.iterator().next() + ':' + ISO9075.encode(elementRef.getQName().getLocalName());
}
}
}
buf.append(elementString);
}
if (children == true)
{
// append syntax to get all children of the path
buf.append("//*");
}
else
{
// append syntax to just represent the path, not the children
buf.append("/*");
}
return buf.toString();
}
/**
* @return Returns the categories to use for the search
*/
public String[] getCategories()
{
return this.categories;
}
/**
* @param categories The categories to set.
*/
public void setCategories(String[] categories)
{
if (categories != null)
{
this.categories = categories;
}
}
/**
* @return Returns the node to search from or null for all.
*/
public String getLocation()
{
return this.location;
}
/**
* @param location The node to search from or null for all..
*/
public void setLocation(String location)
{
this.location = location;
}
/**
* @return Returns the mode to use during the search (see constants)
*/
public int getMode()
{
return this.mode;
}
/**
* @param mode The mode to use during the search (see constants)
*/
public void setMode(int mode)
{
this.mode = mode;
}
/**
* @return Returns the search text string.
*/
public String getText()
{
return this.text;
}
/**
* @param text The search text string.
*/
public void setText(String text)
{
this.text = text;
}
/**
* @return Returns the contentType.
*/
public String getContentType()
{
return this.contentType;
}
/**
* @param contentType The content type to restrict attribute search against.
*/
public void setContentType(String contentType)
{
this.contentType = contentType;
}
/**
* @return Returns the mimeType.
*/
public String getMimeType()
{
return this.mimeType;
}
/**
* @param mimeType The mimeType to set.
*/
public void setMimeType(String mimeType)
{
this.mimeType = mimeType;
}
/**
* @return Returns true to search location children, false for just the specified location.
*/
public boolean getLocationChildren()
{
return this.locationChildren;
}
/**
* @param locationChildren True to search location children, false for just the specified location.
*/
public void setLocationChildren(boolean locationChildren)
{
this.locationChildren = locationChildren;
}
/**
* @return Returns true to search category children, false for just the specified category.
*/
public boolean getCategoryChildren()
{
return this.categoryChildren;
}
/**
* @param categoryChildren True to search category children, false for just the specified category.
*/
public void setCategoryChildren(boolean categoryChildren)
{
this.categoryChildren = categoryChildren;
}
/**
* Add an additional attribute to search against
*
* @param qname QName of the attribute to search against
* @param value Value of the attribute to use
*/
public void addAttributeQuery(QName qname, String value)
{
this.queryAttributes.put(qname, value);
}
/**
* Add an additional range attribute to search against
*
* @param qname QName of the attribute to search against
* @param lower Lower value for range
* @param upper Upper value for range
* @param inclusive True for inclusive within the range, false otherwise
*/
public void addRangeQuery(QName qname, String lower, String upper, boolean inclusive)
{
this.rangeAttributes.put(qname, new RangeProperties(qname, lower, upper, inclusive));
}
/**
* Add an additional fixed value attribute to search against
*
* @param qname QName of the attribute to search against
* @param value Fixed value of the attribute to use
*/
public void addFixedValueQuery(QName qname, String value)
{
this.queryFixedValues.put(qname, value);
}
/**
* Simple wrapper class for range query attribute properties
*/
private static class RangeProperties
{
QName qname;
String lower;
String upper;
boolean inclusive;
RangeProperties(QName qname, String lower, String upper, boolean inclusive)
{
this.qname = qname;
this.lower = lower;
this.upper = upper;
this.inclusive = inclusive;
}
}
}

View File

@@ -0,0 +1,407 @@
/*
* 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.web.bean;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.Utils.URLMode;
import org.alfresco.web.ui.common.component.UIActionLink;
/**
* Back bean provided access to the details of a Space
*
* @author Kevin Roast
*/
public class SpaceDetailsBean
{
private static final String OUTCOME_RETURN = "showSpaceDetails";
/** BrowseBean instance */
private BrowseBean browseBean;
/** The NavigationBean bean reference */
private NavigationBean navigator;
/** PermissionService bean reference */
private PermissionService permissionService;
/** NodeServuce bean reference */
private NodeService nodeService;
/** Selected template Id */
private String template;
// ------------------------------------------------------------------------------
// Bean property getters and setters
/**
* Sets the BrowseBean instance to use to retrieve the current Space
*
* @param browseBean BrowseBean instance
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
/**
* @param navigator The NavigationBean to set.
*/
public void setNavigator(NavigationBean navigator)
{
this.navigator = navigator;
}
/**
* @param nodeService The NodeService to set
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param permissionService The PermissionService to set.
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* Returns the Space this bean is currently representing
*
* @return The Space Node
*/
public Node getSpace()
{
return this.browseBean.getActionSpace();
}
/**
* Returns the id of the current document
*
* @return The id
*/
public String getId()
{
return getSpace().getId();
}
/**
* Returns the name of the current document
*
* @return Name of the current document
*/
public String getName()
{
return getSpace().getName();
}
/**
* Returns the WebDAV URL for the current document
*
* @return The WebDAV url
*/
public String getWebdavUrl()
{
return Utils.generateURL(FacesContext.getCurrentInstance(), getSpace(), URLMode.WEBDAV);
}
/**
* Returns the URL to access the details page for the current document
*
* @return The bookmark URL
*/
public String getBookmarkUrl()
{
return Utils.generateURL(FacesContext.getCurrentInstance(), getSpace(), URLMode.SHOW_DETAILS);
}
/**
* Returns the CIFS path for the current document
*
* @return The CIFS path
*/
public String getCifsPath()
{
return Utils.generateURL(FacesContext.getCurrentInstance(), getSpace(), URLMode.CIFS);
}
/**
* @return Returns the template Id.
*/
public String getTemplate()
{
// return current template if it exists
NodeRef ref = (NodeRef)getSpace().getProperties().get(ContentModel.PROP_TEMPLATE);
return ref != null ? ref.getId() : this.template;
}
/**
* @param template The template Id to set.
*/
public void setTemplate(String template)
{
this.template = template;
}
/**
* @return true if the current document has the 'templatable' aspect applied and
* references a template that currently exists in the system.
*/
public boolean isTemplatable()
{
NodeRef templateRef = (NodeRef)getSpace().getProperties().get(ContentModel.PROP_TEMPLATE);
return (getSpace().hasAspect(ContentModel.ASPECT_TEMPLATABLE) &&
templateRef != null && nodeService.exists(templateRef));
}
/**
* @return String of the NodeRef for the dashboard template used by the space if any
*/
public String getTemplateRef()
{
NodeRef ref = (NodeRef)getSpace().getProperties().get(ContentModel.PROP_TEMPLATE);
return ref != null ? ref.toString() : null;
}
/**
* Returns a model for use by a template on the Space Details page.
*
* @return model containing current current space info.
*/
public Map getTemplateModel()
{
HashMap model = new HashMap(1, 1.0f);
FacesContext fc = FacesContext.getCurrentInstance();
TemplateNode spaceNode = new TemplateNode(getSpace().getNodeRef(), Repository.getServiceRegistry(fc),
new TemplateImageResolver() {
public String resolveImagePathForName(String filename, boolean small) {
return Utils.getFileTypeImage(filename, small);
}
});
model.put("space", spaceNode);
return model;
}
/**
* @return the list of available Content Templates that can be applied to the current document.
*/
public SelectItem[] getTemplates()
{
// get the template from the special Content Templates folder
FacesContext context = FacesContext.getCurrentInstance();
String xpath = Application.getRootPath(context) + "/" +
Application.getGlossaryFolderName(context) + "/" +
Application.getContentTemplatesFolderName(context) + "//*";
NodeRef rootNodeRef = this.nodeService.getRootNode(Repository.getStoreRef());
NamespaceService resolver = Repository.getServiceRegistry(context).getNamespaceService();
List<NodeRef> results = Repository.getServiceRegistry(context).getSearchService().selectNodes(
rootNodeRef, xpath, null, resolver, false);
List<SelectItem> templates = new ArrayList<SelectItem>(results.size());
if (results.size() != 0)
{
DictionaryService dd = Repository.getServiceRegistry(context).getDictionaryService();
for (NodeRef ref : results)
{
Node childNode = new Node(ref);
if (dd.isSubClass(childNode.getType(), ContentModel.TYPE_CONTENT))
{
templates.add(new SelectItem(childNode.getId(), childNode.getName()));
}
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(templates, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
return templates.toArray(new SelectItem[templates.size()]);
}
// ------------------------------------------------------------------------------
// Action event handlers
/**
* Action handler to apply the selected Template and Templatable aspect to the current Space
*/
public String applyTemplate()
{
try
{
// apply the templatable aspect if required
if (getSpace().hasAspect(ContentModel.ASPECT_TEMPLATABLE) == false)
{
this.nodeService.addAspect(getSpace().getNodeRef(), ContentModel.ASPECT_TEMPLATABLE, null);
}
// get the selected template from the Template Picker
NodeRef templateRef = new NodeRef(Repository.getStoreRef(), this.template);
// set the template NodeRef into the templatable aspect property
this.nodeService.setProperty(getSpace().getNodeRef(), ContentModel.PROP_TEMPLATE, templateRef);
// reset space details for next refresh of details page
getSpace().reset();
}
catch (Exception e)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), e.getMessage()), e);
}
return OUTCOME_RETURN;
}
/**
* Action handler to remove a dashboard template from the current Space
*/
public String removeTemplate()
{
try
{
// clear template property
this.nodeService.setProperty(getSpace().getNodeRef(), ContentModel.PROP_TEMPLATE, null);
this.nodeService.removeAspect(getSpace().getNodeRef(), ContentModel.ASPECT_TEMPLATABLE);
// reset space details for next refresh of details page
getSpace().reset();
}
catch (Exception e)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), e.getMessage()), e);
}
return OUTCOME_RETURN;
}
/**
* Navigates to next item in the list of Spaces
*/
public void nextItem(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
List<Node> nodes = this.browseBean.getNodes();
if (nodes.size() > 1)
{
// perform a linear search - this is slow but stateless
// otherwise we would have to manage state of last selected node
// this gets very tricky as this bean is instantiated once and never
// reset - it does not know when the document has changed etc.
for (int i=0; i<nodes.size(); i++)
{
if (id.equals(nodes.get(i).getId()) == true)
{
Node next;
// found our item - navigate to next
if (i != nodes.size() - 1)
{
next = nodes.get(i + 1);
}
else
{
// handle wrapping case
next = nodes.get(0);
}
// prepare for showing details for this node
this.browseBean.setupSpaceAction(next.getId(), false);
}
}
}
}
}
/**
* Navigates to the previous item in the list Spaces
*/
public void previousItem(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
List<Node> nodes = this.browseBean.getNodes();
if (nodes.size() > 1)
{
// see above
for (int i=0; i<nodes.size(); i++)
{
if (id.equals(nodes.get(i).getId()) == true)
{
Node previous;
// found our item - navigate to previous
if (i != 0)
{
previous = nodes.get(i - 1);
}
else
{
// handle wrapping case
previous = nodes.get(nodes.size() - 1);
}
// show details for this node
this.browseBean.setupSpaceAction(previous.getId(), false);
}
}
}
}
}
/**
* Action handler to clear the current Space properties before returning to the browse screen,
* as the user may have modified the properties!
*/
public String closeDialog()
{
this.navigator.resetCurrentNodeProperties();
return "browse";
}
}

View File

@@ -0,0 +1,352 @@
/*
* 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.web.bean;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.repo.component.shelf.UIShortcutsShelfItem;
import org.apache.log4j.Logger;
/**
* This bean manages the user defined list of Recent Spaces in the Shelf component.
*
* @author Kevin Roast
*/
public class UserShortcutsBean
{
private static Logger logger = Logger.getLogger(UserShortcutsBean.class);
/** The NodeService to be used by the bean */
private NodeService nodeService;
/** The BrowseBean reference */
private BrowseBean browseBean;
/** List of shortcut nodes */
private List<Node> shortcuts = null;
private QName QNAME_SHORTCUTS = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "shortcuts");
// ------------------------------------------------------------------------------
// Bean property getters and setters
/**
* @param nodeService The NodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param browseBean The BrowseBean to set.
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
/**
* @return the List of shortcut Nodes
*/
public List<Node> getShortcuts()
{
if (this.shortcuts == null)
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
// get the shortcuts from the preferences for this user
NodeRef prefRef = getShortcutsNodeRef();
List<String> shortcuts = (List<String>)this.nodeService.getProperty(prefRef, QNAME_SHORTCUTS);
if (shortcuts != null)
{
// each shortcut node ID is persisted as a list item in a well known property
this.shortcuts = new ArrayList<Node>(shortcuts.size());
for (int i=0; i<shortcuts.size(); i++)
{
NodeRef ref = new NodeRef(Repository.getStoreRef(), shortcuts.get(i));
if (this.nodeService.exists(ref) == true)
{
Node node = new Node(ref);
// quick init properties while in the usertransaction
node.getProperties();
// save ref to the Node for rendering
this.shortcuts.add(node);
}
else
{
// ignore this shortcut node - no longer exists in the system!
// we write the node list back again afterwards to correct this
if (logger.isDebugEnabled())
logger.debug("Found invalid shortcut node Id: " + ref.getId());
}
}
// if the count of accessable shortcuts is different to our original list then
// write the valid shortcut IDs back to correct invalid node refs
if (this.shortcuts.size() != shortcuts.size())
{
shortcuts = new ArrayList<String>(this.shortcuts.size());
for (int i=0; i<this.shortcuts.size(); i++)
{
shortcuts.add(this.shortcuts.get(i).getId());
}
this.nodeService.setProperty(prefRef, QNAME_SHORTCUTS, (Serializable)shortcuts);
}
}
else
{
this.shortcuts = new ArrayList<Node>(5);
}
tx.commit();
}
catch (Exception err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
return this.shortcuts;
}
/**
* @param spaces List of shortcuts Nodes
*/
public void setShortcuts(List<Node> nodes)
{
this.shortcuts = nodes;
}
// ------------------------------------------------------------------------------
// Action method handlers
/**
* Action handler called when a new shortcut is to be added to the list
*/
public void createShortcut(ActionEvent event)
{
// TODO: add this action to the Details screen for Space and Document
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
try
{
NodeRef ref = new NodeRef(Repository.getStoreRef(), id);
Node node = new Node(ref);
boolean foundShortcut = false;
for (int i=0; i<getShortcuts().size(); i++)
{
if (node.getId().equals(getShortcuts().get(i).getId()))
{
// found same node already in the list - so we don't need to add it again
foundShortcut = true;
break;
}
}
if (foundShortcut == false)
{
// add to persistent store
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
NodeRef prefRef = getShortcutsNodeRef();
List<String> shortcuts = (List<String>)this.nodeService.getProperty(prefRef, QNAME_SHORTCUTS);
if (shortcuts == null)
{
shortcuts = new ArrayList<String>(1);
}
shortcuts.add(node.getNodeRef().getId());
this.nodeService.setProperty(prefRef, QNAME_SHORTCUTS, (Serializable)shortcuts);
// commit the transaction
tx.commit();
// add our new shortcut Node to the in-memory list
getShortcuts().add(node);
if (logger.isDebugEnabled())
logger.debug("Added node: " + node.getName() + " to the user shortcuts list.");
}
catch (Exception err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {id}) );
}
}
}
/**
* Get the node we need to store our user preferences
*/
private NodeRef getShortcutsNodeRef()
{
return Application.getCurrentUser(FacesContext.getCurrentInstance()).getUserPreferencesRef();
}
/**
* Action handler bound to the user shortcuts Shelf component called when a node is removed
*/
public void removeShortcut(ActionEvent event)
{
UIShortcutsShelfItem.ShortcutEvent shortcutEvent = (UIShortcutsShelfItem.ShortcutEvent)event;
// remove from persistent store
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
NodeRef prefRef = getShortcutsNodeRef();
List<String> shortcuts = (List<String>)this.nodeService.getProperty(prefRef, QNAME_SHORTCUTS);
if (shortcuts != null && shortcuts.size() > shortcutEvent.Index)
{
// remove the shortcut from the saved list and persist back
shortcuts.remove(shortcutEvent.Index);
this.nodeService.setProperty(prefRef, QNAME_SHORTCUTS, (Serializable)shortcuts);
// commit the transaction
tx.commit();
// remove shortcut Node from the in-memory list
Node node = getShortcuts().remove(shortcutEvent.Index);
if (logger.isDebugEnabled())
logger.debug("Removed node: " + node.getName() + " from the user shortcuts list.");
}
}
catch (Exception err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
/**
* Action handler bound to the user shortcuts Shelf component called when a node is clicked
*/
public void click(ActionEvent event)
{
// work out which node was clicked from the event data
UIShortcutsShelfItem.ShortcutEvent shortcutEvent = (UIShortcutsShelfItem.ShortcutEvent)event;
Node selectedNode = getShortcuts().get(shortcutEvent.Index);
try
{
DictionaryService dd = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getDictionaryService();
if (dd.isSubClass(selectedNode.getType(), ContentModel.TYPE_FOLDER))
{
// then navigate to the appropriate node in UI
// use browse bean functionality for this as it will update the breadcrumb for us
this.browseBean.updateUILocation(selectedNode.getNodeRef());
}
else if (dd.isSubClass(selectedNode.getType(), ContentModel.TYPE_CONTENT))
{
// view details for document
this.browseBean.setupContentAction(selectedNode.getId(), true);
FacesContext fc = FacesContext.getCurrentInstance();
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "showDocDetails");
}
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {selectedNode.getId()}) );
// remove item from the shortcut list
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
NodeRef prefRef = getShortcutsNodeRef();
List<String> shortcuts = (List<String>)this.nodeService.getProperty(prefRef, QNAME_SHORTCUTS);
if (shortcuts != null && shortcuts.size() > shortcutEvent.Index)
{
// remove the shortcut from the saved list and persist back
shortcuts.remove(shortcutEvent.Index);
this.nodeService.setProperty(prefRef, QNAME_SHORTCUTS, (Serializable)shortcuts);
// commit the transaction
tx.commit();
// remove shortcut Node from the in-memory list
Node node = getShortcuts().remove(shortcutEvent.Index);
if (logger.isDebugEnabled())
logger.debug("Removed deleted node: " + node.getName() + " from the user shortcuts list.");
}
}
catch (Exception err)
{
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
}
}

View File

@@ -0,0 +1,336 @@
/*
* 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.web.bean.clipboard;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.CopyService;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.NavigationBean;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.repo.component.shelf.UIClipboardShelfItem;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author Kevin Roast
*/
public class ClipboardBean
{
// ------------------------------------------------------------------------------
// Bean property getters and setters
/**
* @return Returns the NodeService.
*/
public NodeService getNodeService()
{
return this.nodeService;
}
/**
* @param nodeService The NodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @return Returns the NodeOperationsService.
*/
public CopyService getNodeOperationsService()
{
return this.nodeOperationsService;
}
/**
* @param nodeOperationsService The NodeOperationsService to set.
*/
public void setNodeOperationsService(CopyService nodeOperationsService)
{
this.nodeOperationsService = nodeOperationsService;
}
/**
* @return Returns the navigation bean instance.
*/
public NavigationBean getNavigator()
{
return this.navigator;
}
/**
* @param navigator The NavigationBean to set.
*/
public void setNavigator(NavigationBean navigator)
{
this.navigator = navigator;
}
/**
* @return Returns the clipboard items.
*/
public List<ClipboardItem> getItems()
{
return this.items;
}
/**
* @param items The clipboard items to set.
*/
public void setItems(List<ClipboardItem> items)
{
this.items = items;
}
// ------------------------------------------------------------------------------
// Navigation action event handlers
/**
* Action handler called to add a node to the clipboard for a Copy operation
*/
public void copyNode(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
addClipboardNode(id, ClipboardStatus.COPY);
}
}
/**
* Action handler called to add a node to the clipboard for a Cut operation
*/
public void cutNode(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
addClipboardNode(id, ClipboardStatus.CUT);
}
}
/**
* Action handler call from the browse screen to Paste All clipboard items into the current Space
*/
public void pasteAll(ActionEvent event)
{
performPasteItems(-1);
}
/**
* Action handler called to paste one or all items from the clipboard
*/
public void pasteItem(ActionEvent event)
{
UIClipboardShelfItem.ClipboardEvent clipEvent = (UIClipboardShelfItem.ClipboardEvent)event;
int index = clipEvent.Index;
if (index >= this.items.size())
{
throw new IllegalStateException("Clipboard attempting paste a non existent item index: " + index);
}
performPasteItems(index);
}
/**
* Perform a paste for the specified clipboard item(s)
*
* @param index of clipboard item to paste or -1 for all
*/
private void performPasteItems(int index)
{
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (index == -1)
{
// paste all
for (int i=0; i<this.items.size(); i++)
{
performClipboardOperation(this.items.get(i));
}
// remove the cut operation item from the clipboard
List<ClipboardItem> newItems = new ArrayList<ClipboardItem>(this.items.size());
for (int i=0; i<this.items.size(); i++)
{
ClipboardItem item = this.items.get(i);
if (item.Mode != ClipboardStatus.CUT)
{
newItems.add(item);
}
}
setItems(newItems);
// TODO: after a paste all - remove items from the clipboard...? or not. ask linton
}
else
{
// single paste operation
ClipboardItem item = this.items.get(index);
performClipboardOperation(item);
if (item.Mode == ClipboardStatus.CUT)
{
this.items.remove(index);
}
}
// commit the transaction
tx.commit();
// refresh UI on success
UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
}
catch (Exception err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(Application.getMessage(
FacesContext.getCurrentInstance(), MSG_ERROR_PASTE) + err.getMessage(), err);
}
}
/**
* Perform the operation for the specified clipboard item
*
* @param item
*/
private void performClipboardOperation(ClipboardItem item)
{
NodeRef parentRef = new NodeRef(Repository.getStoreRef(),
this.navigator.getCurrentNodeId());
// TODO: should we use primary parent here?
// The problem is we can't pass round ChildAssocRefs as form params etc. in the UI!
// It's tricky if we need to pass childassocref around everywhere...!
ChildAssociationRef assocRef = this.nodeService.getPrimaryParent(item.Node.getNodeRef());
if (item.Mode == ClipboardStatus.COPY)
{
if (logger.isDebugEnabled())
logger.debug("Trying to copy node ID: " + item.Node.getId() + " into node ID: " + parentRef.getId());
// call the node ops service to initiate the copy
// TODO: should the assoc qname be derived from the type...?
DictionaryService dd = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getDictionaryService();
boolean copyChildren = dd.isSubClass(item.Node.getType(), ContentModel.TYPE_FOLDER);
NodeRef copyRef = this.nodeOperationsService.copy(
item.Node.getNodeRef(),
parentRef,
ContentModel.ASSOC_CONTAINS,
assocRef.getQName(),
copyChildren);
}
else
{
if (logger.isDebugEnabled())
logger.debug("Trying to move node ID: " + item.Node.getId() + " into node ID: " + parentRef.getId());
// move the node
this.nodeService.moveNode(
item.Node.getNodeRef(),
parentRef,
ContentModel.ASSOC_CONTAINS,
assocRef.getQName());
}
}
/**
* Add a clipboard node for an operation to the clipboard
*
* @param id ID of the node for the operation
* @param mode ClipboardStatus for the operation
*/
private void addClipboardNode(String id, ClipboardStatus mode)
{
try
{
NodeRef ref = new NodeRef(Repository.getStoreRef(), id);
// check for duplicates first
ClipboardItem item = new ClipboardItem(new Node(ref), mode);
boolean foundDuplicate = false;
for (int i=0; i<items.size(); i++)
{
if (items.get(i).equals(item))
{
// found a duplicate replace with new instance as copy mode may have changed
items.set(i, item);
foundDuplicate = true;
break;
}
}
// if duplicate not found, then append to list
if (foundDuplicate == false)
{
items.add(item);
}
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {id}) );
}
}
// ------------------------------------------------------------------------------
// Private data
private static Log logger = LogFactory.getLog(ClipboardBean.class);
/** I18N messages */
private static final String MSG_ERROR_PASTE = "error_paste";
/** The NodeService to be used by the bean */
private NodeService nodeService;
/** The NodeOperationsService to be used by the bean */
private CopyService nodeOperationsService;
/** The NavigationBean reference */
private NavigationBean navigator;
/** Current state of the clipboard items */
private List<ClipboardItem> items = new ArrayList<ClipboardItem>(4);
}

View File

@@ -0,0 +1,68 @@
/*
* 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.web.bean.clipboard;
import org.alfresco.web.bean.repository.Node;
/**
* @author Kevin Roast
*/
public class ClipboardItem
{
/**
* Constructor
*
* @param node The node on the clipboard
* @param mode The ClipboardStatus enum value
*/
public ClipboardItem(Node node, ClipboardStatus mode)
{
this.Node = node;
this.Mode = mode;
}
/**
* Override equals() to compare NodeRefs
*/
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (obj instanceof ClipboardItem)
{
return ((ClipboardItem)obj).Node.getNodeRef().equals(Node.getNodeRef());
}
else
{
return false;
}
}
/**
* Override hashCode() to use the internal NodeRef hashcode instead
*/
public int hashCode()
{
return Node.getNodeRef().hashCode();
}
public Node Node;
public ClipboardStatus Mode;
}

View File

@@ -0,0 +1,24 @@
/*
* 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.web.bean.clipboard;
/**
* @author Kevin Roast
*
* Clipboard status for an item.
*/
public enum ClipboardStatus {CUT, COPY}

View File

@@ -0,0 +1,258 @@
/*
* 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.web.bean.preview;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.BrowseBean;
import org.alfresco.web.bean.NavigationBean;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
/**
* Backing bean for the Preview Document in Template action page
*
* @author Kevin Roast
*/
public abstract class BasePreviewBean
{
private static final String NO_SELECTION = "none";
/** BrowseBean instance */
protected BrowseBean browseBean;
/** NodeService instance */
protected NodeService nodeService;
/** The SearchService instance */
protected SearchService searchService;
/** The NavigationBean bean reference */
protected NavigationBean navigator;
protected NodeRef template;
/**
* @param nodeService The nodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param browseBean The BrowseBean to set.
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
/**
* @param searchService The searchService to set.
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @param navigator The NavigationBean to set.
*/
public void setNavigator(NavigationBean navigator)
{
this.navigator = navigator;
}
/**
* Returns the node this bean is currently working with
*
* @return The current Node
*/
public abstract Node getNode();
/**
* Returns the id of the current node
*
* @return The id
*/
public String getId()
{
return getNode().getId();
}
/**
* Returns the name of the current node
*
* @return Name of the current node
*/
public String getName()
{
return getNode().getName();
}
/**
* @return the list of available Content Templates that can be applied to the current document.
*/
public SelectItem[] getTemplates()
{
// TODO: could cache this last for say 1 minute before requerying
// get the template from the special Content Templates folder
FacesContext context = FacesContext.getCurrentInstance();
String xpath = Application.getRootPath(context) + "/" +
Application.getGlossaryFolderName(context) + "/" +
Application.getContentTemplatesFolderName(context) + "//*";
NodeRef rootNodeRef = this.nodeService.getRootNode(Repository.getStoreRef());
NamespaceService resolver = Repository.getServiceRegistry(context).getNamespaceService();
List<NodeRef> results = this.searchService.selectNodes(rootNodeRef, xpath, null, resolver, false);
List<SelectItem> templates = new ArrayList<SelectItem>(results.size());
if (results.size() != 0)
{
DictionaryService dd = Repository.getServiceRegistry(context).getDictionaryService();
for (NodeRef ref : results)
{
Node childNode = new Node(ref);
if (dd.isSubClass(childNode.getType(), ContentModel.TYPE_CONTENT))
{
templates.add(new SelectItem(childNode.getId(), childNode.getName()));
}
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(templates, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
// add an entry (at the start) to instruct the user to select a template
templates.add(0, new SelectItem(NO_SELECTION, Application.getMessage(FacesContext.getCurrentInstance(), "select_a_template")));
return templates.toArray(new SelectItem[templates.size()]);
}
/**
* Returns a model for use by the template on the Preview page.
*
* @return model containing current document/space info.
*/
public abstract Map getTemplateModel();
/** Template Image resolver helper */
protected TemplateImageResolver imageResolver = new TemplateImageResolver()
{
public String resolveImagePathForName(String filename, boolean small)
{
return Utils.getFileTypeImage(filename, small);
}
};
/**
* @return the current template as a full NodeRef
*/
public NodeRef getTemplateRef()
{
return this.template;
}
/**
* @return Returns the template Id.
*/
public String getTemplate()
{
return (this.template != null ? this.template.getId() : null);
}
/**
* @param template The template Id to set.
*/
public void setTemplate(String template)
{
if (template != null && template.equals(NO_SELECTION) == false)
{
this.template = new NodeRef(Repository.getStoreRef(), template);
}
}
private int findNextPreviewNode(List<Node> nodes, int start)
{
// search from start to end of list
for (int i=start; i<nodes.size(); i++)
{
Node next = nodes.get(i);
if (next.hasAspect(ContentModel.ASPECT_TEMPLATABLE))
{
return i;
}
}
// search from zero index to start - 1 (to skip original node)
for (int i=0; i<start - 1; i++)
{
Node next = nodes.get(i);
if (next.hasAspect(ContentModel.ASPECT_TEMPLATABLE))
{
return i;
}
}
return -1;
}
private int findPrevPreviewNode(List<Node> nodes, int start)
{
// search from start to beginning of list
for (int i=start; i>=0; i--)
{
Node next = nodes.get(i);
if (next.hasAspect(ContentModel.ASPECT_TEMPLATABLE))
{
return i;
}
}
// end of list to start + 1 (to skip original node)
for (int i=nodes.size() - 1; i>start; i--)
{
Node next = nodes.get(i);
if (next.hasAspect(ContentModel.ASPECT_TEMPLATABLE))
{
return i;
}
}
return -1;
}
}

View File

@@ -0,0 +1,83 @@
/*
* 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.web.bean.preview;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.BrowseBean;
import org.alfresco.web.bean.NavigationBean;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
/**
* Backing bean for the Preview Document in Template action page
*
* @author Kevin Roast
*/
public class DocumentPreviewBean extends BasePreviewBean
{
/**
* Returns the document this bean is currently representing
*
* @return The document Node
*/
public Node getNode()
{
return this.browseBean.getDocument();
}
/**
* Returns a model for use by a template on the Document Details page.
*
* @return model containing current document and current space info.
*/
public Map getTemplateModel()
{
HashMap model = new HashMap(3, 1.0f);
FacesContext fc = FacesContext.getCurrentInstance();
TemplateNode documentNode = new TemplateNode(getNode().getNodeRef(),
Repository.getServiceRegistry(fc), imageResolver);
model.put("document", documentNode);
TemplateNode spaceNode = new TemplateNode(this.navigator.getCurrentNode().getNodeRef(),
Repository.getServiceRegistry(fc), imageResolver);
model.put("space", spaceNode);
return model;
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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.web.bean.preview;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.BrowseBean;
import org.alfresco.web.bean.NavigationBean;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
/**
* Backing bean for the Preview Space in Template action page
*
* @author Kevin Roast
*/
public class SpacePreviewBean extends BasePreviewBean
{
/**
* Returns the Space this bean is currently representing
*
* @return The Space Node
*/
public Node getNode()
{
return this.browseBean.getActionSpace();
}
/**
* Returns a model for use by a template on the Document Details page.
*
* @return model containing current document and current space info.
*/
public Map getTemplateModel()
{
HashMap model = new HashMap(3, 1.0f);
FacesContext fc = FacesContext.getCurrentInstance();
TemplateNode spaceNode = new TemplateNode(getNode().getNodeRef(),
Repository.getServiceRegistry(fc), imageResolver);
model.put("space", spaceNode);
return model;
}
}

View File

@@ -0,0 +1,135 @@
/*
* 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.web.bean.repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Lighweight client side representation of the repository data dictionary.
* This allows service calls to be kept to a minimum and for bean access, thus enabling JSF
* value binding expressions.
*
* @author gavinc
*/
public final class DataDictionary
{
private static Log logger = LogFactory.getLog(DataDictionary.class);
private DictionaryService dictionaryService;
private NamespaceService namespaceService;
private Map<QName, TypeDefinition> types = new HashMap<QName, TypeDefinition>(11, 1.0f);
/**
* Constructor
*
* @param dictionaryService The dictionary service to use to retrieve the data
*/
public DataDictionary(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* Returns the type definition for the type represented by the given qname
*
* @param type The qname of the type to lookup the definition for
* @return The type definition for the requested type
*/
public TypeDefinition getTypeDef(QName type)
{
TypeDefinition typeDef = types.get(type);
if (typeDef == null)
{
typeDef = this.dictionaryService.getType(type);
if (typeDef != null)
{
types.put(type, typeDef);
}
}
return typeDef;
}
/**
* Returns the type definition for the type represented by the given qname
* and for all the given aspects
*
* @param type The type to retrieve the definition for
* @param optionalAspects A list of aspects to retrieve the definition for
* @return A unified type definition of the given type and aspects
*/
public TypeDefinition getTypeDef(QName type, Collection<QName> optionalAspects)
{
return this.dictionaryService.getAnonymousType(type, optionalAspects);
}
/**
* Returns the property definition for the given property on the given node
*
* @param node The node from which to get the property
* @param property The property to find the definition for
* @return The property definition or null if the property is not known
*/
public PropertyDefinition getPropertyDefinition(Node node, String property)
{
PropertyDefinition propDef = null;
TypeDefinition typeDef = getTypeDef(node.getType(), node.getAspects());
if (typeDef != null)
{
Map<QName, PropertyDefinition> properties = typeDef.getProperties();
propDef = properties.get(Repository.resolveToQName(property));
}
return propDef;
}
/**
* Returns the association definition for the given association on the given node
*
* @param node The node from which to get the association
* @param association The association to find the definition for
* @return The association definition or null if the association is not known
*/
public AssociationDefinition getAssociationDefinition(Node node, String association)
{
AssociationDefinition assocDef = null;
TypeDefinition typeDef = getTypeDef(node.getType(), node.getAspects());
if (typeDef != null)
{
Map<QName, AssociationDefinition> assocs = typeDef.getAssociations();
assocDef = assocs.get(Repository.resolveToQName(association));
}
return assocDef;
}
}

View File

@@ -0,0 +1,179 @@
/*
* 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.web.bean.repository;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
/**
* Lighweight client side representation of a node held in the repository, which
* is modelled as a map for use in the data tables.
*
* @author gavinc
*/
public class MapNode extends Node implements Map<String, Object>
{
private static final long serialVersionUID = 4051322327734433079L;
private boolean propsInitialised = false;
/**
* Constructor
*
* @param nodeRef The NodeRef this Node wrapper represents
*/
public MapNode(NodeRef nodeRef)
{
super(nodeRef);
}
/**
* Constructor
*
* @param nodeRef The NodeRef this Node wrapper represents
* @param nodeService The node service to use to retrieve data for this node
* @param initProps True to immediately init the properties of the node, false to do nothing
*/
public MapNode(NodeRef nodeRef, NodeService nodeService, boolean initProps)
{
super(nodeRef);
if (initProps == true)
{
getProperties();
}
}
// ------------------------------------------------------------------------------
// Map implementation - allows the Node bean to be accessed using JSF expression syntax
/**
* @see java.util.Map#clear()
*/
public void clear()
{
getProperties().clear();
}
/**
* @see java.util.Map#containsKey(java.lang.Object)
*/
public boolean containsKey(Object key)
{
return getProperties().containsKey(key);
}
/**
* @see java.util.Map#containsValue(java.lang.Object)
*/
public boolean containsValue(Object value)
{
return getProperties().containsKey(value);
}
/**
* @see java.util.Map#entrySet()
*/
public Set entrySet()
{
return getProperties().entrySet();
}
/**
* @see java.util.Map#get(java.lang.Object)
*/
public Object get(Object key)
{
Object obj = null;
// there are some things that aren't available as properties
// but from method calls, so for these handle them individually
Map<String, Object> props = getProperties();
if (propsInitialised == false)
{
// well known properties required as publically accessable map attributes
props.put("id", this.getId());
props.put("name", this.getName()); // TODO: perf test pulling back single prop here instead of all!
props.put("nodeRef", this.getNodeRef());
propsInitialised = true;
}
return props.get(key);
}
/**
* @see java.util.Map#isEmpty()
*/
public boolean isEmpty()
{
return getProperties().isEmpty();
}
/**
* @see java.util.Map#keySet()
*/
public Set keySet()
{
return getProperties().keySet();
}
/**
* @see java.util.Map#put(K, V)
*/
public Object put(String key, Object value)
{
return getProperties().put(key, value);
}
/**
* @see java.util.Map#putAll(java.util.Map)
*/
public void putAll(Map t)
{
getProperties().putAll(t);
}
/**
* @see java.util.Map#remove(java.lang.Object)
*/
public Object remove(Object key)
{
return getProperties().remove(key);
}
/**
* @see java.util.Map#size()
*/
public int size()
{
return getProperties().size();
}
/**
* @see java.util.Map#values()
*/
public Collection values()
{
return getProperties().values();
}
}

View File

@@ -0,0 +1,426 @@
/*
* 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.web.bean.repository;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.faces.context.FacesContext;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Lighweight client side representation of a node held in the repository.
*
* @author gavinc
*/
public class Node implements Serializable
{
private static final long serialVersionUID = 3544390322739034169L;
protected static Log logger = LogFactory.getLog(Node.class);
protected NodeRef nodeRef;
private String name;
private QName type;
private String path;
private String id;
private Set<QName> aspects = null;
private Map<String, Boolean> permissions;
protected QNameNodeMap<String, Object> properties;
protected boolean propsRetrieved = false;
protected ServiceRegistry services = null;
private boolean childAssocsRetrieved = false;
private QNameNodeMap childAssociations;
private Map<String, Map<String, ChildAssociationRef>> childAssociationsAdded;
private Map<String, Map<String, ChildAssociationRef>> childAssociationsRemoved;
private boolean assocsRetrieved = false;
private QNameNodeMap associations;
private Map<String, Map<String, AssociationRef>> associationsAdded;
private Map<String, Map<String, AssociationRef>> associationsRemoved;
/**
* Constructor
*
* @param nodeRef The NodeRef this Node wrapper represents
*/
public Node(NodeRef nodeRef)
{
if (nodeRef == null)
{
throw new IllegalArgumentException("NodeRef must be supplied for creation of a Node.");
}
this.nodeRef = nodeRef;
this.id = nodeRef.getId();
this.properties = new QNameNodeMap<String, Object>(getServiceRegistry().getNamespaceService(), this);
}
/**
* @return All the properties known about this node.
*/
public Map<String, Object> getProperties()
{
if (this.propsRetrieved == false)
{
Map<QName, Serializable> props = getServiceRegistry().getNodeService().getProperties(this.nodeRef);
for (QName qname: props.keySet())
{
Serializable propValue = props.get(qname);
this.properties.put(qname.toString(), propValue);
}
this.propsRetrieved = true;
}
return this.properties;
}
/**
* @return All the associations this node has as a Map, using the association
* type as the key
*/
public final Map getAssociations()
{
if (this.assocsRetrieved == false)
{
associations = new QNameNodeMap(getServiceRegistry().getNamespaceService(), this);
List<AssociationRef> assocs = getServiceRegistry().getNodeService().getTargetAssocs(this.nodeRef, RegexQNamePattern.MATCH_ALL);
for (AssociationRef assocRef: assocs)
{
String assocName = assocRef.getTypeQName().toString();
List list = (List)this.associations.get(assocName);
// create the list if this is first association with 'assocName'
if (list == null)
{
list = new ArrayList<AssociationRef>();
this.associations.put(assocName, list);
}
// add the association to the list
list.add(assocRef);
}
this.assocsRetrieved = true;
}
return this.associations;
}
/**
* Returns all the associations added to this node in this UI session
*
* @return Map of Maps of AssociationRefs
*/
public final Map<String, Map<String, AssociationRef>> getAddedAssociations()
{
if (this.associationsAdded == null)
{
this.associationsAdded = new HashMap<String, Map<String, AssociationRef>>();
}
return this.associationsAdded;
}
/**
* Returns all the associations removed from this node is this UI session
*
* @return Map of Maps of AssociationRefs
*/
public final Map<String, Map<String, AssociationRef>> getRemovedAssociations()
{
if (this.associationsRemoved == null)
{
this.associationsRemoved = new HashMap<String, Map<String, AssociationRef>>();
}
return this.associationsRemoved;
}
/**
* @return All the child associations this node has as a Map, using the association
* type as the key
*/
public final Map getChildAssociations()
{
if (this.childAssocsRetrieved == false)
{
this.childAssociations = new QNameNodeMap(getServiceRegistry().getNamespaceService(), this);
List<ChildAssociationRef> assocs = getServiceRegistry().getNodeService().getChildAssocs(this.nodeRef);
for (ChildAssociationRef assocRef: assocs)
{
String assocName = assocRef.getTypeQName().toString();
List list = (List)this.childAssociations.get(assocName);
// create the list if this is first association with 'assocName'
if (list == null)
{
list = new ArrayList<ChildAssociationRef>();
this.childAssociations.put(assocName, list);
}
// add the association to the list
list.add(assocRef);
}
this.childAssocsRetrieved = true;
}
return this.childAssociations;
}
/**
* Returns all the child associations added to this node in this UI session
*
* @return Map of Maps of ChildAssociationRefs
*/
public final Map<String, Map<String, ChildAssociationRef>> getAddedChildAssociations()
{
if (this.childAssociationsAdded == null)
{
this.childAssociationsAdded = new HashMap<String, Map<String, ChildAssociationRef>>();
}
return this.childAssociationsAdded;
}
/**
* Returns all the child associations removed from this node is this UI session
*
* @return Map of Maps of ChildAssociationRefs
*/
public final Map<String, Map<String, ChildAssociationRef>> getRemovedChildAssociations()
{
if (this.childAssociationsRemoved == null)
{
this.childAssociationsRemoved = new HashMap<String, Map<String, ChildAssociationRef>>();
}
return this.childAssociationsRemoved;
}
/**
* Register a property resolver for the named property.
*
* @param name Name of the property this resolver is for
* @param resolver Property resolver to register
*/
public final void addPropertyResolver(String name, NodePropertyResolver resolver)
{
this.properties.addPropertyResolver(name, resolver);
}
/**
* Determines whether the given property name is held by this node
*
* @param propertyName Property to test existence of
* @return true if property exists, false otherwise
*/
public final boolean hasProperty(String propertyName)
{
return getProperties().containsKey(propertyName);
}
/**
* @return Returns the NodeRef this Node object represents
*/
public final NodeRef getNodeRef()
{
return this.nodeRef;
}
/**
* @return Returns the type.
*/
public final QName getType()
{
if (this.type == null)
{
this.type = getServiceRegistry().getNodeService().getType(this.nodeRef);
}
return type;
}
/**
* @return The display name for the node
*/
public final String getName()
{
if (this.name == null)
{
// try and get the name from the properties first
this.name = (String)getProperties().get("cm:name");
// if we didn't find it as a property get the name from the association name
if (this.name == null)
{
this.name = getServiceRegistry().getNodeService().getPrimaryParent(this.nodeRef).getQName().getLocalName();
}
}
return this.name;
}
/**
* @return The list of aspects applied to this node
*/
public final Set<QName> getAspects()
{
if (this.aspects == null)
{
this.aspects = getServiceRegistry().getNodeService().getAspects(this.nodeRef);
}
return this.aspects;
}
/**
* @param aspect The aspect to test for
* @return true if the node has the aspect false otherwise
*/
public final boolean hasAspect(QName aspect)
{
Set aspects = getAspects();
return aspects.contains(aspect);
}
/**
* Return whether the current user has the specified access permission on this Node
*
* @param permission Permission to validate against
*
* @return true if the permission is applied to the node for this user, false otherwise
*/
public final boolean hasPermission(String permission)
{
Boolean valid = null;
if (permissions != null)
{
valid = permissions.get(permission);
}
else
{
permissions = new HashMap<String, Boolean>(5, 1.0f);
}
if (valid == null)
{
PermissionService service = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getPermissionService();
valid = Boolean.valueOf(service.hasPermission(this.nodeRef, permission) == AccessStatus.ALLOWED);
permissions.put(permission, valid);
}
return valid.booleanValue();
}
/**
* @return The GUID for the node
*/
public final String getId()
{
return this.id;
}
/**
* @return The path for the node
*/
public final String getPath()
{
if (this.path == null)
{
this.path = getServiceRegistry().getNodeService().getPath(this.nodeRef).toString();
}
return this.path;
}
/**
* Resets the state of the node to force re-retrieval of the data
*/
public void reset()
{
this.name = null;
this.type = null;
this.path = null;
this.properties.clear();
this.propsRetrieved = false;
this.aspects = null;
this.permissions = null;
this.associations = null;
this.associationsAdded = null;
this.associationsRemoved = null;
this.assocsRetrieved = false;
this.childAssociations = null;
this.childAssociationsAdded = null;
this.childAssociationsRemoved = null;
this.childAssocsRetrieved = false;
}
/**
* Override Object.toString() to provide useful debug output
*/
public String toString()
{
if (getServiceRegistry().getNodeService() != null)
{
if (getServiceRegistry().getNodeService().exists(nodeRef))
{
return "Node Type: " + getType() +
"\nNode Properties: " + this.getProperties().toString() +
"\nNode Aspects: " + this.getAspects().toString();
}
else
{
return "Node no longer exists: " + nodeRef;
}
}
else
{
return super.toString();
}
}
protected ServiceRegistry getServiceRegistry()
{
if (this.services == null)
{
this.services = Repository.getServiceRegistry(FacesContext.getCurrentInstance());
}
return this.services;
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.web.bean.repository;
/**
* Simple interface used to implement small classes capable of calculating dynamic property values
* for Nodes at runtime. This allows bean responsible for building large lists of Nodes to
* encapsulate the code needed to retrieve non-standard Node properties. The values are then
* calculated on demand by the property resolver.
*
* When a node is reset() the standard and other props are cleared. If property resolvers are used
* then the non-standard props will be restored automatically as well.
*
* @author Kevin Roast
*/
public interface NodePropertyResolver
{
/**
* Get the property value for this resolver
*
* @param node Node this property is for
*
* @return property value
*/
public Object get(Node node);
}

View File

@@ -0,0 +1,121 @@
/*
* 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.web.bean.repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.QNameMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A extension of the repo QNameMap to provide custom property resolving support for Node wrappers.
*
* @author Kevin Roast
*/
public final class QNameNodeMap<K,V> extends QNameMap implements Map, Cloneable
{
private Node parent = null;
private Map<String, NodePropertyResolver> resolvers = new HashMap<String, NodePropertyResolver>(11, 1.0f);
/**
* Constructor
*
* @param parent Parent Node of the QNameNodeMap
*/
public QNameNodeMap(NamespacePrefixResolver resolver, Node parent)
{
super(resolver);
if (parent == null)
{
throw new IllegalArgumentException("Parent Node cannot be null!");
}
this.parent = parent;
}
/**
* Register a property resolver for the named property.
*
* @param name Name of the property this resolver is for
* @param resolver Property resolver to register
*/
public void addPropertyResolver(String name, NodePropertyResolver resolver)
{
this.resolvers.put(name, resolver);
}
/**
* @see java.util.Map#containsKey(java.lang.Object)
*/
public boolean containsKey(Object key)
{
return (this.contents.containsKey(Repository.resolveToQNameString((String)key)) ||
this.resolvers.containsKey(key));
}
/**
* @see java.util.Map#get(java.lang.Object)
*/
public Object get(Object key)
{
String qnameKey = Repository.resolveToQNameString(key.toString());
Object obj = this.contents.get(qnameKey);
if (obj == null)
{
// if a property resolver exists for this property name then invoke it
NodePropertyResolver resolver = this.resolvers.get(key.toString());
if (resolver != null)
{
obj = resolver.get(this.parent);
// cache the result
// obviously the cache is useless if the result is null, in most cases it shouldn't be
this.contents.put(qnameKey, obj);
}
}
return obj;
}
/**
* Perform a get without using property resolvers
*
* @param key item key
* @return object
*/
public Object getRaw(Object key)
{
return this.contents.get(Repository.resolveToQNameString((String)key));
}
/**
* Shallow copy the map by copying keys and values into a new QNameNodeMap
*/
public Object clone()
{
QNameNodeMap map = new QNameNodeMap(this.resolver, this.parent);
map.putAll(this);
if (this.resolvers.size() != 0)
{
map.resolvers = (Map)((HashMap)this.resolvers).clone();
}
return map;
}
}

View File

@@ -0,0 +1,620 @@
/*
* 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.web.bean.repository;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.configuration.ConfigurableService;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.metadata.MetadataExtracter;
import org.alfresco.repo.content.metadata.MetadataExtracterRegistry;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.app.Application;
import org.alfresco.web.ui.common.Utils;
import org.apache.log4j.Logger;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.jsf.FacesContextUtils;
/**
* Helper class for accessing repository objects, convert values, escape values and service utilities.
*
* @author gavinc
* @author kevinr
*/
public final class Repository
{
/** I18N error messages */
public static final String ERROR_NODEREF = "error_noderef";
public static final String ERROR_GENERIC = "error_generic";
public static final String ERROR_NOHOME = "error_homespace";
public static final String ERROR_SEARCH = "error_search";
private static final String METADATA_EXTACTER_REGISTRY = "metadataExtracterRegistry";
private static Logger logger = Logger.getLogger(Repository.class);
/** cache of client StoreRef */
private static StoreRef storeRef = null;
/** reference to Person folder */
private static NodeRef peopleRef = null;
/** reference to System folder */
private static NodeRef systemRef = null;
/** reference to the namespace service */
private static NamespaceService namespaceService = null;
/**
* Private constructor
*/
private Repository()
{
}
/**
* Returns a store reference object
*
* @return A StoreRef object
*/
public static StoreRef getStoreRef()
{
return storeRef;
}
/**
* Returns a store reference object.
* This method is used to setup the cached value by the ContextListener initialisation methods
*
* @return The StoreRef object
*/
public static StoreRef getStoreRef(ServletContext context)
{
storeRef = Application.getRepositoryStoreRef(context);
return storeRef;
}
/**
* Helper to get the display name for a Node.
* The method will attempt to use the "name" attribute, if not found it will revert to using
* the QName.getLocalName() retrieved from the primary parent relationship.
*
* @param ref NodeRef
*
* @return display name string for the specified Node.
*/
public static String getNameForNode(NodeService nodeService, NodeRef ref)
{
String name = null;
// try to find a display "name" property for this node
Object nameProp = nodeService.getProperty(ref, ContentModel.PROP_NAME);
if (nameProp != null)
{
name = nameProp.toString();
}
else
{
// revert to using QName if not found
QName qname = nodeService.getPrimaryParent(ref).getQName();
if (qname != null)
{
name = qname.getLocalName();
}
}
return name;
}
/**
* Escape a QName value so it can be used in lucene search strings
*
* @param qName QName to escape
*
* @return escaped value
*/
public static String escapeQName(QName qName)
{
String string = qName.toString();
StringBuilder buf = new StringBuilder(string.length() + 4);
for (int i = 0; i < string.length(); i++)
{
char c = string.charAt(i);
if ((c == '{') || (c == '}') || (c == ':') || (c == '-'))
{
buf.append('\\');
}
buf.append(c);
}
return buf.toString();
}
/**
* Return whether a Node is currently locked
*
* @param node The Node wrapper to test against
* @param lockService The LockService to use
*
* @return whether a Node is currently locked
*/
public static Boolean isNodeLocked(Node node, LockService lockService)
{
Boolean locked = Boolean.FALSE;
if (node.hasAspect(ContentModel.ASPECT_LOCKABLE))
{
LockStatus lockStatus = lockService.getLockStatus(node.getNodeRef());
if (lockStatus == LockStatus.LOCKED || lockStatus == LockStatus.LOCK_OWNER)
{
locked = Boolean.TRUE;
}
}
return locked;
}
/**
* Return whether a Node is currently locked by the current user
*
* @param node The Node wrapper to test against
* @param lockService The LockService to use
*
* @return whether a Node is currently locked by the current user
*/
public static Boolean isNodeOwnerLocked(Node node, LockService lockService)
{
Boolean locked = Boolean.FALSE;
if (node.hasAspect(ContentModel.ASPECT_LOCKABLE) &&
lockService.getLockStatus(node.getNodeRef()) == LockStatus.LOCK_OWNER)
{
locked = Boolean.TRUE;
}
return locked;
}
/**
* Return whether a WorkingCopy Node is owned by the current User
*
* @param node The Node wrapper to test against
* @param lockService The LockService to use
*
* @return whether a WorkingCopy Node is owned by the current User
*/
public static Boolean isNodeOwner(Node node, LockService lockService)
{
Boolean locked = Boolean.FALSE;
if (node.hasAspect(ContentModel.ASPECT_WORKING_COPY))
{
Object obj = node.getProperties().get("workingCopyOwner");
if (obj instanceof String)
{
User user = Application.getCurrentUser(FacesContext.getCurrentInstance());
if ( ((String)obj).equals(user.getUserName()))
{
locked = Boolean.TRUE;
}
}
}
return locked;
}
/**
* Return the human readable form of the specified node Path. Fast version of the method that
* simply converts QName localname components to Strings.
*
* @param path Path to extract readable form from, excluding the final element
*
* @return human readable form of the Path excluding the final element
*/
public static String getDisplayPath(Path path)
{
StringBuilder buf = new StringBuilder(64);
for (int i=0; i<path.size()-1; i++)
{
String elementString = null;
Path.Element element = path.get(i);
if (element instanceof Path.ChildAssocElement)
{
ChildAssociationRef elementRef = ((Path.ChildAssocElement)element).getRef();
if (elementRef.getParentRef() != null)
{
elementString = elementRef.getQName().getLocalName();
}
}
else
{
elementString = element.getElementString();
}
if (elementString != null)
{
buf.append("/");
buf.append(elementString);
}
}
return buf.toString();
}
/**
* Resolve a Path by converting each element into its display NAME attribute
*
* @param path Path to convert
* @param separator Separator to user between path elements
* @param prefix To prepend to the path
*
* @return Path converted using NAME attribute on each element
*/
public static String getNamePath(NodeService nodeService, Path path, NodeRef rootNode, String separator, String prefix)
{
StringBuilder buf = new StringBuilder(128);
// ignore root node check if not passed in
boolean foundRoot = (rootNode == null);
buf.append(prefix);
// skip first element as it represents repo root '/'
for (int i=1; i<path.size(); i++)
{
Path.Element element = path.get(i);
String elementString = null;
if (element instanceof Path.ChildAssocElement)
{
ChildAssociationRef elementRef = ((Path.ChildAssocElement)element).getRef();
if (elementRef.getParentRef() != null)
{
// only append if we've found the root already
if (foundRoot == true)
{
Object nameProp = nodeService.getProperty(elementRef.getChildRef(), ContentModel.PROP_NAME);
if (nameProp != null)
{
elementString = nameProp.toString();
}
else
{
elementString = element.getElementString();
}
}
// either we've found root already or may have now
// check after as we want to skip the root as it represents the CIFS share name
foundRoot = (foundRoot || elementRef.getChildRef().equals(rootNode));
}
}
else
{
elementString = element.getElementString();
}
if (elementString != null)
{
buf.append(separator);
buf.append(elementString);
}
}
return buf.toString();
}
/**
* Return the mimetype code for the specified file name.
* <p>
* The file extension will be extracted from the filename and used to lookup the mimetype.
*
* @param context FacesContext
* @param filename Non-null filename to process
*
* @return mimetype for the specified filename - falls back to 'application/octet-stream' if not found.
*/
public static String getMimeTypeForFileName(FacesContext context, String filename)
{
// base the mimetype from the file extension
MimetypeService mimetypeService = (MimetypeService)getServiceRegistry(context).getMimetypeService();
// fall back to binary mimetype if no match found
String mimetype = MimetypeMap.MIMETYPE_BINARY;
int extIndex = filename.lastIndexOf('.');
if (extIndex != -1)
{
String ext = filename.substring(extIndex + 1).toLowerCase();
String mt = mimetypeService.getMimetypesByExtension().get(ext);
if (mt != null)
{
mimetype = mt;
}
}
return mimetype;
}
/**
* Return a UserTransaction instance
*
* @param context FacesContext
*
* @return UserTransaction
*/
public static UserTransaction getUserTransaction(FacesContext context)
{
TransactionService transactionService = getServiceRegistry(context).getTransactionService();
return transactionService.getUserTransaction();
}
/**
* Return a UserTransaction instance
*
* @param context FacesContext
* @param readonly Transaction readonly state
*
* @return UserTransaction
*/
public static UserTransaction getUserTransaction(FacesContext context, boolean readonly)
{
TransactionService transactionService = getServiceRegistry(context).getTransactionService();
return transactionService.getUserTransaction(readonly);
}
/**
* Return the Repository Service Registry
*
* @param context Faces Context
* @return the Service Registry
*/
public static ServiceRegistry getServiceRegistry(FacesContext context)
{
return (ServiceRegistry)FacesContextUtils.getRequiredWebApplicationContext(
context).getBean(ServiceRegistry.SERVICE_REGISTRY);
}
/**
* Return the Repository Service Registry
*
* @param context Servlet Context
* @return the Service Registry
*/
public static ServiceRegistry getServiceRegistry(ServletContext context)
{
return (ServiceRegistry)WebApplicationContextUtils.getRequiredWebApplicationContext(
context).getBean(ServiceRegistry.SERVICE_REGISTRY);
}
/**
* Return the Configurable Service
*
* @return the configurable service
*/
public static ConfigurableService getConfigurableService(FacesContext context)
{
return (ConfigurableService)FacesContextUtils.getRequiredWebApplicationContext(context).getBean("configurableService");
}
/**
* Return the Metadata Extracter Registry
*
* @param context Faces Context
* @return the MetadataExtracterRegistry
*/
public static MetadataExtracterRegistry getMetadataExtracterRegistry(FacesContext context)
{
return (MetadataExtracterRegistry)FacesContextUtils.getRequiredWebApplicationContext(
context).getBean(METADATA_EXTACTER_REGISTRY);
}
/**
* Extracts the metadata of a "raw" piece of content into a map.
*
* @param context Faces Context
* @param reader Content reader for the source content to extract from
* @param destination Map of metadata to set metadata values into
* @return True if an extracter was found
*/
public static boolean extractMetadata(FacesContext context, ContentReader reader, Map<QName, Serializable> destination)
{
// check that source mimetype is available
String mimetype = reader.getMimetype();
if (mimetype == null)
{
throw new AlfrescoRuntimeException("The content reader mimetype must be set: " + reader);
}
// look for a transformer
MetadataExtracter extracter = getMetadataExtracterRegistry(context).getExtracter(mimetype);
if (extracter == null)
{
// No metadata extracter is not a failure, but we flag it
return false;
}
// we have a transformer, so do it
extracter.extract(reader, destination);
return true;
}
/**
* Query a list of Person type nodes from the repo
* It is currently assumed that all Person nodes exist below the Repository root node
*
* @param context Faces Context
* @param nodeService The node service
* @param searchService used to perform the search
* @return List of Person node objects
*/
public static List<Node> getUsers(FacesContext context, NodeService nodeService, SearchService searchService)
{
List<Node> personNodes = null;
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(context, true);
tx.begin();
PersonService personService = (PersonService)FacesContextUtils.getRequiredWebApplicationContext(context).getBean("personService");
NodeRef peopleRef = personService.getPeopleContainer();
// TODO: better to perform an XPath search or a get for a specific child type here?
List<ChildAssociationRef> childRefs = nodeService.getChildAssocs(peopleRef);
personNodes = new ArrayList<Node>(childRefs.size());
for (ChildAssociationRef ref: childRefs)
{
// create our Node representation from the NodeRef
NodeRef nodeRef = ref.getChildRef();
if (nodeService.getType(nodeRef).equals(ContentModel.TYPE_PERSON))
{
// create our Node representation
MapNode node = new MapNode(nodeRef);
// set data binding properties
// this will also force initialisation of the props now during the UserTransaction
// it is much better for performance to do this now rather than during page bind
Map<String, Object> props = node.getProperties();
props.put("fullName", ((String)props.get("firstName")) + ' ' + ((String)props.get("lastName")));
NodeRef homeFolderNodeRef = (NodeRef)props.get("homeFolder");
if (homeFolderNodeRef != null)
{
props.put("homeSpace", homeFolderNodeRef);
}
personNodes.add(node);
}
}
// commit the transaction
tx.commit();
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
context, Repository.ERROR_NODEREF), new Object[] {"root"}) );
personNodes = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
catch (Exception err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
context, Repository.ERROR_GENERIC), err.getMessage()), err );
personNodes = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
return personNodes;
}
/**
* Convert a property of unknown type to a String value. A native String value will be
* returned directly, else toString() will be executed, null is returned as null.
*
* @param value Property value
*
* @return value to String or null
*/
public static String safePropertyToString(Serializable value)
{
if (value == null)
{
return null;
}
else if (value instanceof String)
{
return (String)value;
}
else
{
return value.toString();
}
}
/**
* Creates a QName representation for the given String.
* If the String has no namespace the Alfresco namespace is added.
* If the String has a prefix an attempt to resolve the prefix to the
* full URI will be made.
*
* @param str The string to convert
* @return A QName representation of the given string
*/
public static QName resolveToQName(String str)
{
return QName.resolveToQName(getNamespaceService(), str);
}
/**
* Creates a string representation of a QName for the given string.
* If the given string already has a namespace, either a URL or a prefix,
* nothing the given string is returned. If it does not have a namespace
* the Alfresco namespace is added.
*
* @param str The string to convert
* @return A QName String representation of the given string
*/
public static String resolveToQNameString(String str)
{
return QName.resolveToQNameString(getNamespaceService(), str);
}
/**
* Returns an instance of the namespace service
*
* @return The NamespaceService
*/
private static NamespaceService getNamespaceService()
{
if (namespaceService == null)
{
ServiceRegistry svcReg = getServiceRegistry(FacesContext.getCurrentInstance());
namespaceService = svcReg.getNamespaceService();
}
return namespaceService;
}
}

View File

@@ -0,0 +1,200 @@
/*
* 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.web.bean.repository;
import java.util.List;
import javax.faces.context.FacesContext;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.configuration.ConfigurableService;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
/**
* Bean that represents the currently logged in user
*
* @author gavinc
*/
public final class User
{
private String homeSpaceId;
private String userName;
private String ticket;
private NodeRef person;
private String fullName = null;
private Boolean administrator = null;
/** cached ref to our user preferences node */
private NodeRef preferencesFolderRef = null;
/**
* Constructor
*
* @param userName constructor for the user
*/
public User(String userName, String ticket, NodeRef person)
{
if (userName == null || ticket == null || person == null)
{
throw new IllegalArgumentException("All user details are mandatory!");
}
this.userName = userName;
this.ticket = ticket;
this.person = person;
}
/**
* @return The user name
*/
public String getUserName()
{
return this.userName;
}
/**
* Return the full name of the Person this User represents
*
* @param service NodeService to use
*
* @return The full name
*/
public String getFullName(NodeService service)
{
if (this.fullName == null)
{
this.fullName = service.getProperty(this.person, ContentModel.PROP_FIRSTNAME) + " " +
service.getProperty(this.person, ContentModel.PROP_LASTNAME);
}
return this.fullName;
}
/**
* @return Retrieves the user's home space (this may be the id of the company home space)
*/
public String getHomeSpaceId()
{
return this.homeSpaceId;
}
/**
* @param homeSpaceId Sets the id of the users home space
*/
public void setHomeSpaceId(String homeSpaceId)
{
this.homeSpaceId = homeSpaceId;
}
/**
* @return Returns the ticket.
*/
public String getTicket()
{
return this.ticket;
}
/**
* @return Returns the person NodeRef
*/
public NodeRef getPerson()
{
return this.person;
}
/**
* @return If the current user has Admin Authority
*/
public boolean isAdmin()
{
if (administrator == null)
{
administrator = Repository.getServiceRegistry(FacesContext.getCurrentInstance())
.getAuthorityService().hasAdminAuthority();
}
return administrator;
}
/**
* Get or create the node used to store user preferences.
* Utilises the 'configurable' aspect on the Person linked to this user.
*/
public synchronized NodeRef getUserPreferencesRef()
{
if (this.preferencesFolderRef == null)
{
FacesContext fc = FacesContext.getCurrentInstance();
ServiceRegistry registry = Repository.getServiceRegistry(fc);
NodeService nodeService = registry.getNodeService();
SearchService searchService = registry.getSearchService();
NamespaceService namespaceService = registry.getNamespaceService();
ConfigurableService configurableService = Repository.getConfigurableService(fc);
NodeRef person = Application.getCurrentUser(fc).getPerson();
if (nodeService.hasAspect(person, ContentModel.ASPECT_CONFIGURABLE) == false)
{
// create the configuration folder for this Person node
configurableService.makeConfigurable(person);
}
// target of the assoc is the configurations folder ref
NodeRef configRef = configurableService.getConfigurationFolder(person);
if (configRef == null)
{
throw new IllegalStateException("Unable to find associated 'configurations' folder for node: " + person);
}
String xpath = NamespaceService.APP_MODEL_PREFIX + ":" + "preferences";
List<NodeRef> nodes = searchService.selectNodes(
configRef,
xpath,
null,
namespaceService,
false);
NodeRef prefRef;
if (nodes.size() == 1)
{
prefRef = nodes.get(0);
}
else
{
// create the preferences Node for this user
ChildAssociationRef childRef = nodeService.createNode(
configRef,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "preferences"),
ContentModel.TYPE_CMOBJECT);
prefRef = childRef.getChildRef();
}
this.preferencesFolderRef = prefRef;
}
return this.preferencesFolderRef;
}
}

View File

@@ -0,0 +1,633 @@
/*
* 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.web.bean.users;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.faces.application.FacesMessage;
import javax.faces.component.UISelectOne;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.BrowseBean;
import org.alfresco.web.bean.repository.MapNode;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.data.UIRichList;
import org.alfresco.web.ui.repo.WebResources;
/**
* @author Kevin Roast
*/
public class UserMembersBean
{
private static final String MSG_SUCCESS_INHERIT_NOT = "success_not_inherit_permissions";
private static final String MSG_SUCCESS_INHERIT = "success_inherit_permissions";
private static final String ERROR_DELETE = "error_remove_user";
private static final String OUTCOME_FINISH = "finish";
/** NodeService bean reference */
private NodeService nodeService;
/** SearchService bean reference */
private SearchService searchService;
/** PermissionService bean reference */
private PermissionService permissionService;
/** PersonService bean reference */
private PersonService personService;
/** BrowseBean bean refernce */
private BrowseBean browseBean;
/** OwnableService bean reference */
private OwnableService ownableService;
/** Component reference for Users RichList control */
private UIRichList usersRichList;
/** action context */
private String personAuthority = null;
/** action context */
private String personName = null;
/** datamodel for table of roles for current person */
private DataModel personRolesDataModel = null;
/** roles for current person */
private List<PermissionWrapper> personRoles = null;
// ------------------------------------------------------------------------------
// Bean property getters and setters
/**
* @param nodeService The NodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param searchService The search service
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @param permissionService The PermissionService to set.
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* @param ownableService The ownableService to set.
*/
public void setOwnableService(OwnableService ownableService)
{
this.ownableService = ownableService;
}
/**
* @param personService The personService to set.
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
/**
* @param browseBean The BrowseBean to set.
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
/**
* @return The space to work against
*/
public Node getSpace()
{
return this.browseBean.getActionSpace();
}
/**
* @return Returns the usersRichList.
*/
public UIRichList getUsersRichList()
{
return this.usersRichList;
}
/**
* @param usersRichList The usersRichList to set.
*/
public void setUsersRichList(UIRichList usersRichList)
{
this.usersRichList = usersRichList;
// force refresh on exit of the page (as this property is set by JSF on view restore)
this.usersRichList.setValue(null);
}
/**
* Returns the properties for current Person roles JSF DataModel
*
* @return JSF DataModel representing the current Person roles
*/
public DataModel getPersonRolesDataModel()
{
if (this.personRolesDataModel == null)
{
this.personRolesDataModel = new ListDataModel();
}
this.personRolesDataModel.setWrappedData(this.personRoles);
return this.personRolesDataModel;
}
/**
* @return Returns the current person authority.
*/
public String getPersonAuthority()
{
return this.personAuthority;
}
/**
* @param person The person person authority to set.
*/
public void setPersonAuthority(String person)
{
this.personAuthority = person;
}
/**
* @return Returns the personName.
*/
public String getPersonName()
{
return this.personName;
}
/**
* @param personName The personName to set.
*/
public void setPersonName(String personName)
{
this.personName = personName;
}
/**
* @return true if the current user can change permissions on this Space
*/
public boolean getHasChangePermissions()
{
return getSpace().hasPermission(PermissionService.CHANGE_PERMISSIONS);
}
/**
* @return Returns the inherit parent permissions flag set for the current space.
*/
public boolean isInheritPermissions()
{
return this.permissionService.getInheritParentPermissions(getSpace().getNodeRef());
}
/**
* @param inheritPermissions The inheritPermissions to set.
*/
public void setInheritPermissions(boolean inheritPermissions)
{
// stub - no impl as changes are made immediately using a ValueChanged listener
}
/**
* Return the owner username
*/
public String getOwner()
{
return this.ownableService.getOwner(getSpace().getNodeRef());
}
/**
* @return the list of user nodes for list data binding
*/
public List<Map> getUsers()
{
FacesContext context = FacesContext.getCurrentInstance();
List<Map> personNodes = null;
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(context, true);
tx.begin();
// Return all the permissions set against the current node
// for any authentication instance (user).
// Then combine them into a single list for each authentication found.
User user = Application.getCurrentUser(context);
Map<String, List<String>> permissionMap = new HashMap<String, List<String>>(13, 1.0f);
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(getSpace().getNodeRef());
if (permissions != null)
{
for (AccessPermission permission : permissions)
{
// we are only interested in Allow and not groups/owner etc.
if (permission.getAccessStatus() == AccessStatus.ALLOWED &&
(permission.getAuthorityType() == AuthorityType.USER ||
permission.getAuthorityType() == AuthorityType.GROUP ||
permission.getAuthorityType() == AuthorityType.EVERYONE))
{
String authority = permission.getAuthority();
List<String> userPermissions = permissionMap.get(authority);
if (userPermissions == null)
{
// create for first time
userPermissions = new ArrayList<String>(4);
permissionMap.put(authority, userPermissions);
}
// add the permission name for this authority
userPermissions.add(permission.getPermission());
}
}
}
// for each authentication (username key) found we get the Person
// node represented by it and use that for our list databinding object
personNodes = new ArrayList<Map>(permissionMap.size());
for (String authority : permissionMap.keySet())
{
// check if we are dealing with a person (User Authority)
if (personService.personExists(authority))
{
NodeRef nodeRef = personService.getPerson(authority);
if (nodeRef != null)
{
// create our Node representation
MapNode node = new MapNode(nodeRef);
// set data binding properties
// this will also force initialisation of the props now during the UserTransaction
// it is much better for performance to do this now rather than during page bind
Map<String, Object> props = node.getProperties();
props.put("fullName", ((String)props.get("firstName")) + ' ' + ((String)props.get("lastName")));
String userName = (String)props.get("userName");
props.put("roles", listToString(context, permissionMap.get(authority)));
props.put("icon", WebResources.IMAGE_PERSON);
personNodes.add(node);
}
}
else
{
// need a map (dummy node) to represent props for this Group Authority
Map<String, Object> node = new HashMap<String, Object>(5, 1.0f);
node.put("fullName", authority.substring(PermissionService.GROUP_PREFIX.length()));
node.put("userName", authority);
node.put("id", authority);
node.put("roles", listToString(context, permissionMap.get(authority)));
node.put("icon", WebResources.IMAGE_GROUP);
personNodes.add(node);
}
}
// commit the transaction
tx.commit();
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
context, Repository.ERROR_NODEREF), new Object[] {"root"}) );
personNodes = Collections.<Map>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
catch (Exception err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
context, Repository.ERROR_GENERIC), err.getMessage()), err );
personNodes = Collections.<Map>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
return personNodes;
}
private static String listToString(FacesContext context, List<String> list)
{
StringBuilder buf = new StringBuilder();
if (list != null)
{
for (int i=0; i<list.size(); i++)
{
if (buf.length() != 0)
{
buf.append(", ");
}
buf.append(Application.getMessage(context, list.get(i)));
}
}
return buf.toString();
}
// ------------------------------------------------------------------------------
// Action event handlers
/**
* Action event called by all actions that need to setup a Person context on
* the UserMembers bean before an action page is called. The context will be a
* Authority in setPersonAuthority() which can be retrieved on the action page from
* UserMembersBean.setPersonAuthority().
*/
public void setupUserAction(ActionEvent event)
{
FacesContext context = FacesContext.getCurrentInstance();
UIActionLink link = (UIActionLink) event.getComponent();
Map<String, String> params = link.getParameterMap();
String authority = params.get("userName");
if (authority != null && authority.length() != 0)
{
try
{
if (this.personService.personExists(authority))
{
// create the node ref, then our node representation
NodeRef ref = personService.getPerson(authority);
Node node = new Node(ref);
// setup convience function for current user full name
setPersonName((String)node.getProperties().get(ContentModel.PROP_FIRSTNAME) + ' ' +
(String)node.getProperties().get(ContentModel.PROP_LASTNAME));
}
else
{
setPersonName(authority);
}
// setup roles for this Authority
List<PermissionWrapper> userPermissions = new ArrayList<PermissionWrapper>(4);
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(getSpace().getNodeRef());
if (permissions != null)
{
for (AccessPermission permission : permissions)
{
// we are only interested in Allow permissions
if (permission.getAccessStatus() == AccessStatus.ALLOWED)
{
if (authority.equals(permission.getAuthority()))
{
// found a permission for this user authentiaction
PermissionWrapper wrapper = new PermissionWrapper(
permission.getPermission(),
Application.getMessage(context, permission.getPermission()));
userPermissions.add(wrapper);
}
}
}
}
// action context setup
this.personRoles = userPermissions;
setPersonAuthority(authority);
}
catch (Exception err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(FacesContext
.getCurrentInstance(), Repository.ERROR_GENERIC), new Object[] { err.getMessage() }));
}
}
else
{
setPersonAuthority(null);
}
}
/**
* Inherit parent Space permissions value changed by the user
*/
public void inheritPermissionsValueChanged(ValueChangeEvent event)
{
try
{
// change the value to the new selected value
boolean inheritPermissions = (Boolean)event.getNewValue();
this.permissionService.setInheritParentPermissions(getSpace().getNodeRef(), inheritPermissions);
// inform the user that the change occured
FacesContext context = FacesContext.getCurrentInstance();
String msg;
if (inheritPermissions)
{
msg = Application.getMessage(context, MSG_SUCCESS_INHERIT);
}
else
{
msg = Application.getMessage(context, MSG_SUCCESS_INHERIT_NOT);
}
FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg);
context.addMessage(event.getComponent().getClientId(context), facesMsg);
}
catch (Throwable e)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), e.getMessage()), e);
}
}
/**
* Action handler called when the Add Role button is pressed to process the current selection
*/
public void addRole(ActionEvent event)
{
UISelectOne rolePicker = (UISelectOne)event.getComponent().findComponent("roles");
String role = (String)rolePicker.getValue();
if (role != null)
{
FacesContext context = FacesContext.getCurrentInstance();
PermissionWrapper wrapper = new PermissionWrapper(role, Application.getMessage(context, role));
this.personRoles.add(wrapper);
}
}
/**
* Action handler called when the Remove button is pressed to remove a role from current user
*/
public void removeRole(ActionEvent event)
{
PermissionWrapper wrapper = (PermissionWrapper)this.personRolesDataModel.getRowData();
if (wrapper != null)
{
this.personRoles.remove(wrapper);
}
}
/**
* Action handler called when the Finish button is clicked on the Edit User Roles page
*/
public String finishOK()
{
String outcome = OUTCOME_FINISH;
FacesContext context = FacesContext.getCurrentInstance();
// persist new user permissions
if (this.personRoles != null && getPersonAuthority() != null)
{
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(context);
tx.begin();
// clear the currently set permissions for this user
// and add each of the new permissions in turn
NodeRef nodeRef = getSpace().getNodeRef();
this.permissionService.clearPermission(nodeRef, getPersonAuthority());
for (PermissionWrapper wrapper : personRoles)
{
this.permissionService.setPermission(
nodeRef,
getPersonAuthority(),
wrapper.getPermission(),
true);
}
tx.commit();
}
catch (Exception err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
context, Repository.ERROR_GENERIC), err.getMessage()), err );
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
outcome = null;
}
}
return outcome;
}
/**
* Action handler called when the OK button is clicked on the Remove User page
*/
public String removeOK()
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
// remove the invited User
if (getPersonAuthority() != null)
{
// clear permissions for the specified Authority
this.permissionService.clearPermission(getSpace().getNodeRef(), getPersonAuthority());
}
// commit the transaction
tx.commit();
}
catch (Exception e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(FacesContext
.getCurrentInstance(), ERROR_DELETE), e.getMessage()), e);
}
return OUTCOME_FINISH;
}
// ------------------------------------------------------------------------------
// Inner classes
/**
* Wrapper class for list data model to display current roles for user
*/
public static class PermissionWrapper
{
public PermissionWrapper(String permission, String label)
{
this.permission = permission;
this.label = label;
}
public String getRole()
{
return this.label;
}
public String getPermission()
{
return this.permission;
}
private String label;
private String permission;
}
}

View File

@@ -0,0 +1,311 @@
/*
* 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.web.bean.users;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.IContextListener;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.LoginBean;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.data.UIRichList;
import org.apache.log4j.Logger;
/**
* @author Kevin Roast
*/
public class UsersBean implements IContextListener
{
private static Logger logger = Logger.getLogger(UsersBean.class);
public static final String ERROR_PASSWORD_MATCH = "error_password_match";
private static final String ERROR_DELETE = "error_delete_user";
private static final String DEFAULT_OUTCOME = "manageUsers";
/** NodeService bean reference */
private NodeService nodeService;
/** SearchService bean reference */
private SearchService searchService;
/** AuthenticationService bean reference */
private AuthenticationService authenticationService;
/** Component reference for Users RichList control */
private UIRichList usersRichList;
/** action context */
private Node person = null;
private String password = null;
private String confirm = null;
// ------------------------------------------------------------------------------
// Construction
/**
* Default Constructor
*/
public UsersBean()
{
UIContextService.getInstance(FacesContext.getCurrentInstance()).registerBean(this);
}
// ------------------------------------------------------------------------------
// Bean property getters and setters
/**
* @param nodeService The NodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param searchService the search service
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @param authenticationService The AuthenticationService to set.
*/
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
/**
* @return Returns the usersRichList.
*/
public UIRichList getUsersRichList()
{
return this.usersRichList;
}
/**
* @param usersRichList The usersRichList to set.
*/
public void setUsersRichList(UIRichList usersRichList)
{
this.usersRichList = usersRichList;
}
/**
* @return the list of user Nodes to display
*/
public List<Node> getUsers()
{
return Repository.getUsers(FacesContext.getCurrentInstance(), this.nodeService,
this.searchService);
}
/**
* @return Returns the confirm password.
*/
public String getConfirm()
{
return this.confirm;
}
/**
* @param confirm The confirm password to set.
*/
public void setConfirm(String confirm)
{
this.confirm = confirm;
}
/**
* @return Returns the password.
*/
public String getPassword()
{
return this.password;
}
/**
* @param password The password to set.
*/
public void setPassword(String password)
{
this.password = password;
}
/**
* @return Returns the person context.
*/
public Node getPerson()
{
return this.person;
}
/**
* @param person The person context to set.
*/
public void setPerson(Node person)
{
this.person = person;
}
/**
* Action event called by all actions that need to setup a Person context on
* the Users bean before an action page is called. The context will be a
* Person Node in setPerson() which can be retrieved on the action page from
* UsersBean.getPerson().
*/
public void setupUserAction(ActionEvent event)
{
UIActionLink link = (UIActionLink) event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
if (logger.isDebugEnabled())
logger.debug("Setup for action, setting current Person to: " + id);
try
{
// create the node ref, then our node representation
NodeRef ref = new NodeRef(Repository.getStoreRef(), id);
Node node = new Node(ref);
// remember the Person node
setPerson(node);
// clear the UI state in preparation for finishing the action
// and returning to the main page
contextUpdated();
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(FacesContext
.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] { id }));
}
}
else
{
setPerson(null);
}
}
/**
* Action handler called when the OK button is clicked on the Delete User page
*/
public String deleteOK()
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
// we only delete the user auth if Alfresco is managing the authentication
Map session = context.getExternalContext().getSessionMap();
if (session.get(LoginBean.LOGIN_EXTERNAL_AUTH) == null)
{
// delete the User authentication
authenticationService.deleteAuthentication((String) getPerson().getProperties().get("userName"));
}
// delete the associated Person
this.nodeService.deleteNode(getPerson().getNodeRef());
// commit the transaction
tx.commit();
}
catch (Exception e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(FacesContext
.getCurrentInstance(), ERROR_DELETE), e.getMessage()), e);
}
return DEFAULT_OUTCOME;
}
/**
* Action handler called for OK button press on Change Password screen
*/
public String changePasswordOK()
{
String outcome = DEFAULT_OUTCOME;
if (this.password != null && this.confirm != null && this.password.equals(this.confirm))
{
try
{
String userName = (String)this.person.getProperties().get(ContentModel.PROP_USERNAME);
this.authenticationService.setAuthentication(userName, this.password.toCharArray());
}
catch (Exception e)
{
outcome = null;
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(FacesContext
.getCurrentInstance(), Repository.ERROR_GENERIC), e.getMessage()), e);
}
}
else
{
outcome = null;
Utils.addErrorMessage(Application.getMessage(FacesContext.getCurrentInstance(),
ERROR_PASSWORD_MATCH));
}
return outcome;
}
// ------------------------------------------------------------------------------
// IContextListener implementation
/**
* @see org.alfresco.web.app.context.IContextListener#contextUpdated()
*/
public void contextUpdated()
{
if (this.usersRichList != null)
{
this.usersRichList.setValue(null);
}
}
}

View File

@@ -0,0 +1,314 @@
/*
* 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.web.bean.wizard;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.BrowseBean;
import org.alfresco.web.bean.NavigationBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Abstract bean used as the base class for all wizard backing beans.
*
* @author gavinc
*/
public abstract class AbstractWizardBean
{
private static Log logger = LogFactory.getLog(AbstractWizardBean.class);
/** I18N messages */
private static final String MSG_NOT_SET = "value_not_set";
protected static final String FINISH_OUTCOME = "finish";
protected static final String CANCEL_OUTCOME = "cancel";
protected static final String DEFAULT_INSTRUCTION_ID = "default_instruction";
protected static final String SUMMARY_TITLE_ID = "summary";
protected static final String SUMMARY_DESCRIPTION_ID = "summary_desc";
// common wizard properties
protected int currentStep = 1;
protected boolean editMode = false;
protected NodeService nodeService;
protected FileFolderService fileFolderService;
protected SearchService searchService;
protected NavigationBean navigator;
protected BrowseBean browseBean;
/**
* @return Returns the wizard description
*/
public abstract String getWizardDescription();
/**
* @return Returns the wizard title
*/
public abstract String getWizardTitle();
/**
* @return Returns the title for the current step
*/
public abstract String getStepTitle();
/**
* @return Returns the description for the current step
*/
public abstract String getStepDescription();
/**
* @return Returns the instructional text for the current step
*/
public abstract String getStepInstructions();
/**
* Determines the outcome string for the given step number
*
* @param step The step number to get the outcome for
* @return The outcome
*/
protected abstract String determineOutcomeForStep(int step);
/**
* Handles the finish button being pressed
*
* @return The finish outcome
*/
public abstract String finish();
/**
* Action listener called when the wizard is being launched allowing
* state to be setup
*/
public void startWizard(ActionEvent event)
{
// refresh the UI, calling this method now is fine as it basically makes sure certain
// beans clear the state - so when we finish the wizard other beans will have been reset
UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
// make sure the wizard is not in edit mode
this.editMode = false;
// initialise the wizard in case we are launching
// after it was navigated away from
init();
if (logger.isDebugEnabled())
logger.debug("Started wizard : " + getWizardTitle());
}
/**
* Action listener called when the wizard is being launched for
* editing an existing node.
*/
public void startWizardForEdit(ActionEvent event)
{
// refresh the UI, calling this method now is fine as it basically makes sure certain
// beans clear the state - so when we finish the wizard other beans will have been reset
UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
// set the wizard in edit mode
this.editMode = true;
// populate the wizard's default values with the current value
// from the node being edited
init();
populate();
if (logger.isDebugEnabled())
logger.debug("Started wizard : " + getWizardTitle() + " for editing");
}
/**
* Deals with the next button being pressed
*
* @return
*/
public String next()
{
this.currentStep++;
// determine which page to go to next
String outcome = determineOutcomeForStep(this.currentStep);
if (logger.isDebugEnabled())
{
logger.debug("current step is now: " + this.currentStep);
logger.debug("Next outcome: " + outcome);
}
// return the outcome for navigation
return outcome;
}
/**
* Deals with the back button being pressed
*
* @return
*/
public String back()
{
this.currentStep--;
// determine which page to go to next
String outcome = determineOutcomeForStep(this.currentStep);
if (logger.isDebugEnabled())
{
logger.debug("current step is now: " + this.currentStep);
logger.debug("Back outcome: " + outcome);
}
// return the outcome for navigation
return outcome;
}
/**
* Handles the cancelling of the wizard
*
* @return The cancel outcome
*/
public String cancel()
{
// reset the state
init();
return CANCEL_OUTCOME;
}
/**
* Initialises the wizard
*/
public void init()
{
this.currentStep = 1;
}
/**
* Populates the wizard's values with the current values
* of the node about to be edited
*/
public void populate()
{
// subclasses will override this method to setup accordingly
}
/**
* @return Returns the nodeService.
*/
public NodeService getNodeService()
{
return this.nodeService;
}
/**
* @param nodeService The nodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param fileFolderService used to manipulate folder/folder model nodes
*/
public void setFileFolderService(FileFolderService fileFolderService)
{
this.fileFolderService = fileFolderService;
}
/**
* @param searchService the service used to find nodes
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @return Returns the navigation bean instance.
*/
public NavigationBean getNavigator()
{
return navigator;
}
/**
* @param navigator The NavigationBean to set.
*/
public void setNavigator(NavigationBean navigator)
{
this.navigator = navigator;
}
/**
* @return The BrowseBean
*/
public BrowseBean getBrowseBean()
{
return this.browseBean;
}
/**
* @param browseBean The BrowseBean to set.
*/
public void setBrowseBean(BrowseBean browseBean)
{
this.browseBean = browseBean;
}
/**
* Build summary table from the specified list of Labels and Values
*
* @param labels Array of labels to display
* @param values Array of values to display
*
* @return summary table HTML
*/
protected String buildSummary(String[] labels, String[] values)
{
if (labels == null || values == null || labels.length != values.length)
{
throw new IllegalArgumentException("Labels and Values passed to summary must be valid and of equal length.");
}
String msg = Application.getMessage(FacesContext.getCurrentInstance(), MSG_NOT_SET);
String notSetMsg = "&lt;" + msg + "&gt;";
StringBuilder buf = new StringBuilder(256);
buf.append("<table cellspacing='4' cellpadding='2' border='0' class='summary'>");
for (int i=0; i<labels.length; i++)
{
String value = values[i];
buf.append("<tr><td valign='top'><b>");
buf.append(labels[i]);
buf.append(":</b></td><td>");
buf.append(value != null ? value : notSetMsg);
buf.append("</td></tr>");
}
buf.append("</table>");
return buf.toString();
}
}

View File

@@ -0,0 +1,320 @@
/*
* 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.web.bean.wizard;
import java.io.File;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import javax.faces.context.FacesContext;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.FileUploadBean;
import org.alfresco.web.bean.repository.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Handler class used by the Add Content Wizard
*
* @author gavinc
*/
public class AddContentWizard extends BaseContentWizard
{
private static Log logger = LogFactory.getLog(AddContentWizard.class);
// TODO: retrieve these from the config service
private static final String WIZARD_TITLE_ID = "add_content_title";
private static final String WIZARD_DESC_ID = "add_content_desc";
private static final String STEP1_TITLE_ID = "add_conent_step1_title";
private static final String STEP1_DESCRIPTION_ID = "add_conent_step1_desc";
private static final String STEP2_TITLE_ID = "add_conent_step2_title";
private static final String STEP2_DESCRIPTION_ID = "add_conent_step2_desc";
// add content wizard specific properties
private File file;
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#next()
*/
public String next()
{
String outcome = super.next();
// if the outcome is "properties" we pre-set the content type and other
// fields accordingly
if (outcome.equals("properties"))
{
this.contentType = Repository.getMimeTypeForFileName(
FacesContext.getCurrentInstance(), this.fileName);
// set default for in-line editing flag
this.inlineEdit = (this.contentType.equals(MimetypeMap.MIMETYPE_HTML));
// Try and extract metadata from the file
ContentReader cr = new FileContentReader(this.file);
cr.setMimetype(this.contentType);
// create properties for content type
Map<QName, Serializable> contentProps = new HashMap<QName, Serializable>(5, 1.0f);
if (Repository.extractMetadata(FacesContext.getCurrentInstance(), cr, contentProps))
{
this.author = (String)(contentProps.get(ContentModel.PROP_CREATOR));
this.title = (String)(contentProps.get(ContentModel.PROP_TITLE));
this.description = (String)(contentProps.get(ContentModel.PROP_DESCRIPTION));
}
if (this.title == null)
{
this.title = this.fileName;
}
}
return outcome;
}
/**
* Deals with the finish button being pressed
*
* @return outcome
*/
public String finish()
{
String outcome = saveContent(this.file, null);
// now we know the new details are in the repository, reset the
// client side node representation so the new details are retrieved
if (this.editMode)
{
this.browseBean.getDocument().reset();
}
return outcome;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardDescription()
*/
public String getWizardDescription()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_DESC_ID);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardTitle()
*/
public String getWizardTitle()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_TITLE_ID);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepDescription()
*/
public String getStepDescription()
{
String stepDesc = null;
switch (this.currentStep)
{
case 1:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), STEP1_DESCRIPTION_ID);
break;
}
case 2:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), STEP2_DESCRIPTION_ID);
break;
}
case 3:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), SUMMARY_DESCRIPTION_ID);
break;
}
default:
{
stepDesc = "";
}
}
return stepDesc;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepTitle()
*/
public String getStepTitle()
{
String stepTitle = null;
switch (this.currentStep)
{
case 1:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP1_TITLE_ID);
break;
}
case 2:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP2_TITLE_ID);
break;
}
case 3:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), SUMMARY_TITLE_ID);
break;
}
default:
{
stepTitle = "";
}
}
return stepTitle;
}
/**
* Initialises the wizard
*/
public void init()
{
super.init();
clearUpload();
this.file = null;
}
/**
* @return Returns the message to display when a file has been uploaded
*/
public String getFileUploadSuccessMsg()
{
String msg = Application.getMessage(FacesContext.getCurrentInstance(), "file_upload_success");
return MessageFormat.format(msg, new Object[] {getFileName()});
}
/**
* @return Returns the name of the file
*/
public String getFileName()
{
// try and retrieve the file and filename from the file upload bean
// representing the file we previously uploaded.
FacesContext ctx = FacesContext.getCurrentInstance();
FileUploadBean fileBean = (FileUploadBean)ctx.getExternalContext().getSessionMap().
get(FileUploadBean.FILE_UPLOAD_BEAN_NAME);
if (fileBean != null)
{
this.file = fileBean.getFile();
this.fileName = fileBean.getFileName();
}
return this.fileName;
}
/**
* @param fileName The name of the file
*/
public void setFileName(String fileName)
{
this.fileName = fileName;
// we also need to keep the file upload bean in sync
FacesContext ctx = FacesContext.getCurrentInstance();
FileUploadBean fileBean = (FileUploadBean)ctx.getExternalContext().getSessionMap().
get(FileUploadBean.FILE_UPLOAD_BEAN_NAME);
if (fileBean != null)
{
fileBean.setFileName(this.fileName);
}
}
/**
* @return Returns the summary data for the wizard.
*/
public String getSummary()
{
ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance());
return buildSummary(
new String[] {bundle.getString("file_name"), bundle.getString("type"),
bundle.getString("content_type"), bundle.getString("title"),
bundle.getString("description"), bundle.getString("author"),
bundle.getString("inline_editable")},
new String[] {this.fileName, getSummaryObjectType(), getSummaryContentType(), this.title,
this.description, this.author, Boolean.toString(this.inlineEdit)});
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#determineOutcomeForStep(int)
*/
protected String determineOutcomeForStep(int step)
{
String outcome = null;
switch(step)
{
case 1:
{
outcome = "upload";
break;
}
case 2:
{
outcome = "properties";
break;
}
case 3:
{
outcome = "summary";
break;
}
default:
{
outcome = CANCEL_OUTCOME;
}
}
return outcome;
}
/**
* Deletes the uploaded file and removes the FileUploadBean from the session
*/
private void clearUpload()
{
// delete the temporary file we uploaded earlier
if (this.file != null)
{
this.file.delete();
}
// remove the file upload bean from the session
FacesContext ctx = FacesContext.getCurrentInstance();
ctx.getExternalContext().getSessionMap().remove(FileUploadBean.FILE_UPLOAD_BEAN_NAME);
}
}

View File

@@ -0,0 +1,921 @@
/*
* 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.web.bean.wizard;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import org.alfresco.config.Config;
import org.alfresco.config.ConfigElement;
import org.alfresco.config.ConfigService;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.executer.AddFeaturesActionExecuter;
import org.alfresco.repo.action.executer.CheckInActionExecuter;
import org.alfresco.repo.action.executer.CheckOutActionExecuter;
import org.alfresco.repo.action.executer.CopyActionExecuter;
import org.alfresco.repo.action.executer.ImageTransformActionExecuter;
import org.alfresco.repo.action.executer.ImporterActionExecuter;
import org.alfresco.repo.action.executer.LinkCategoryActionExecuter;
import org.alfresco.repo.action.executer.MailActionExecuter;
import org.alfresco.repo.action.executer.MoveActionExecuter;
import org.alfresco.repo.action.executer.SimpleWorkflowActionExecuter;
import org.alfresco.repo.action.executer.SpecialiseTypeActionExecuter;
import org.alfresco.repo.action.executer.TransformActionExecuter;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.ActionDefinition;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.jsf.FacesContextUtils;
/**
* Base handler class containing common code used by the New Space Wizard and New Action Wizard
*
* @author gavinc kevinr
*/
public abstract class BaseActionWizard extends AbstractWizardBean
{
// parameter names for actions
public static final String PROP_CATEGORY = "category";
public static final String PROP_ASPECT = "aspect";
public static final String PROP_DESTINATION = "destinationLocation";
public static final String PROP_APPROVE_STEP_NAME = "approveStepName";
public static final String PROP_APPROVE_ACTION = "approveAction";
public static final String PROP_APPROVE_FOLDER = "approveFolder";
public static final String PROP_REJECT_STEP_PRESENT = "rejectStepPresent";
public static final String PROP_REJECT_STEP_NAME = "rejectStepName";
public static final String PROP_REJECT_ACTION = "rejectAction";
public static final String PROP_REJECT_FOLDER = "rejectFolder";
public static final String PROP_CHECKIN_DESC = "checkinDescription";
public static final String PROP_CHECKIN_MINOR = "checkinMinorChange";
public static final String PROP_TRANSFORMER = "transformer";
public static final String PROP_IMAGE_TRANSFORMER = "imageTransformer";
public static final String PROP_TRANSFORM_OPTIONS = "transformOptions";
public static final String PROP_ENCODING = "encoding";
public static final String PROP_MESSAGE = "message";
public static final String PROP_SUBJECT = "subject";
public static final String PROP_TO = "to";
public static final String PROP_OBJECT_TYPE = "objecttype";
private static final Log logger = LogFactory.getLog(BaseActionWizard.class);
private static final String IMPORT_ENCODING = "UTF-8";
// new rule/action wizard specific properties
protected boolean multiActionMode = false;
protected String action;
protected ActionService actionService;
protected DictionaryService dictionaryService;
protected MimetypeService mimetypeService;
protected List<SelectItem> actions;
protected List<SelectItem> transformers;
protected List<SelectItem> imageTransformers;
protected List<SelectItem> aspects;
protected List<SelectItem> users;
protected List<SelectItem> encodings;
protected Map<String, String> actionDescriptions;
protected Map<String, Serializable> currentActionProperties;
protected List<SelectItem> objectTypes;
/**
* Initialises the wizard
*/
public void init()
{
super.init();
this.action = "add-features";
this.users = null;
this.actions = null;
this.actionDescriptions = null;
this.currentActionProperties = new HashMap<String, Serializable>(3);
// default the approve and reject actions
this.currentActionProperties.put(PROP_APPROVE_ACTION, "move");
this.currentActionProperties.put(PROP_REJECT_STEP_PRESENT, "yes");
this.currentActionProperties.put(PROP_REJECT_ACTION, "move");
// default the checkin minor change
this.currentActionProperties.put(PROP_CHECKIN_MINOR, new Boolean(true));
}
/**
* Build the param map for the current Action instance
*
* @return param map
*/
protected Map<String, Serializable> buildActionParams()
{
// set up parameters maps for the action
Map<String, Serializable> actionParams = new HashMap<String, Serializable>();
if (this.action.equals(AddFeaturesActionExecuter.NAME))
{
QName aspect = Repository.resolveToQName((String)this.currentActionProperties.get(PROP_ASPECT));
actionParams.put(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, aspect);
}
else if (this.action.equals(CopyActionExecuter.NAME))
{
// add the destination space id to the action properties
NodeRef destNodeRef = (NodeRef)this.currentActionProperties.get(PROP_DESTINATION);
actionParams.put(CopyActionExecuter.PARAM_DESTINATION_FOLDER, destNodeRef);
// add the type and name of the association to create when the copy
// is performed
actionParams.put(CopyActionExecuter.PARAM_ASSOC_TYPE_QNAME,
ContentModel.ASSOC_CONTAINS);
actionParams.put(CopyActionExecuter.PARAM_ASSOC_QNAME,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "copy"));
}
else if (this.action.equals(MoveActionExecuter.NAME))
{
// add the destination space id to the action properties
NodeRef destNodeRef = (NodeRef)this.currentActionProperties.get(PROP_DESTINATION);
actionParams.put(MoveActionExecuter.PARAM_DESTINATION_FOLDER, destNodeRef);
// add the type and name of the association to create when the move
// is performed
actionParams.put(MoveActionExecuter.PARAM_ASSOC_TYPE_QNAME,
ContentModel.ASSOC_CONTAINS);
actionParams.put(MoveActionExecuter.PARAM_ASSOC_QNAME,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "move"));
}
else if (this.action.equals(SimpleWorkflowActionExecuter.NAME))
{
// add the approve step name
actionParams.put(SimpleWorkflowActionExecuter.PARAM_APPROVE_STEP,
(String)this.currentActionProperties.get(PROP_APPROVE_STEP_NAME));
// add whether the approve step will copy or move the content
boolean approveMove = true;
String approveAction = (String)this.currentActionProperties.get(PROP_APPROVE_ACTION);
if (approveAction != null && approveAction.equals("copy"))
{
approveMove = false;
}
actionParams.put(SimpleWorkflowActionExecuter.PARAM_APPROVE_MOVE, Boolean.valueOf(approveMove));
// add the destination folder of the content
NodeRef approveDestNodeRef = null;
Object approveDestNode = this.currentActionProperties.get(PROP_APPROVE_FOLDER);
if (approveDestNode instanceof NodeRef)
{
approveDestNodeRef = (NodeRef)approveDestNode;
}
else if (approveDestNode instanceof String)
{
approveDestNodeRef = new NodeRef((String)approveDestNode);
}
actionParams.put(SimpleWorkflowActionExecuter.PARAM_APPROVE_FOLDER, approveDestNodeRef);
// determine whether we have a reject step or not
boolean requireReject = true;
String rejectStepPresent = (String)this.currentActionProperties.get(PROP_REJECT_STEP_PRESENT);
if (rejectStepPresent != null && rejectStepPresent.equals("no"))
{
requireReject = false;
}
if (requireReject)
{
// add the reject step name
actionParams.put(SimpleWorkflowActionExecuter.PARAM_REJECT_STEP,
(String)this.currentActionProperties.get(PROP_REJECT_STEP_NAME));
// add whether the reject step will copy or move the content
boolean rejectMove = true;
String rejectAction = (String)this.currentActionProperties.get(PROP_REJECT_ACTION);
if (rejectAction != null && rejectAction.equals("copy"))
{
rejectMove = false;
}
actionParams.put(SimpleWorkflowActionExecuter.PARAM_REJECT_MOVE, Boolean.valueOf(rejectMove));
// add the destination folder of the content
NodeRef rejectDestNodeRef = null;
Object rejectDestNode = this.currentActionProperties.get(PROP_REJECT_FOLDER);
if (rejectDestNode instanceof NodeRef)
{
rejectDestNodeRef = (NodeRef)rejectDestNode;
}
else if (rejectDestNode instanceof String)
{
rejectDestNodeRef = new NodeRef((String)rejectDestNode);
}
actionParams.put(SimpleWorkflowActionExecuter.PARAM_REJECT_FOLDER, rejectDestNodeRef);
}
}
else if (this.action.equals(LinkCategoryActionExecuter.NAME))
{
// add the classifiable aspect
actionParams.put(LinkCategoryActionExecuter.PARAM_CATEGORY_ASPECT,
ContentModel.ASPECT_GEN_CLASSIFIABLE);
// put the selected category in the action params
NodeRef catNodeRef = (NodeRef)this.currentActionProperties.get(PROP_CATEGORY);
actionParams.put(LinkCategoryActionExecuter.PARAM_CATEGORY_VALUE,
catNodeRef);
}
else if (this.action.equals(CheckOutActionExecuter.NAME))
{
// specify the location the checked out working copy should go
// add the destination space id to the action properties
NodeRef destNodeRef = (NodeRef)this.currentActionProperties.get(PROP_DESTINATION);
actionParams.put(CheckOutActionExecuter.PARAM_DESTINATION_FOLDER, destNodeRef);
// add the type and name of the association to create when the
// check out is performed
actionParams.put(CheckOutActionExecuter.PARAM_ASSOC_TYPE_QNAME,
ContentModel.ASSOC_CONTAINS);
actionParams.put(CheckOutActionExecuter.PARAM_ASSOC_QNAME,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "checkout"));
}
else if (this.action.equals(CheckInActionExecuter.NAME))
{
// add the description for the checkin to the action params
actionParams.put(CheckInActionExecuter.PARAM_DESCRIPTION,
this.currentActionProperties.get(PROP_CHECKIN_DESC));
// add the minor change flag
actionParams.put(CheckInActionExecuter.PARAM_MINOR_CHANGE,
this.currentActionProperties.get(PROP_CHECKIN_MINOR));
}
else if (this.action.equals(TransformActionExecuter.NAME))
{
// add the transformer to use
actionParams.put(TransformActionExecuter.PARAM_MIME_TYPE,
this.currentActionProperties.get(PROP_TRANSFORMER));
// add the destination space id to the action properties
NodeRef destNodeRef = (NodeRef)this.currentActionProperties.get(PROP_DESTINATION);
actionParams.put(TransformActionExecuter.PARAM_DESTINATION_FOLDER, destNodeRef);
// add the type and name of the association to create when the copy
// is performed
actionParams.put(TransformActionExecuter.PARAM_ASSOC_TYPE_QNAME,
ContentModel.ASSOC_CONTAINS);
actionParams.put(TransformActionExecuter.PARAM_ASSOC_QNAME,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "copy"));
}
else if (this.action.equals(ImageTransformActionExecuter.NAME))
{
// add the transformer to use
actionParams.put(ImageTransformActionExecuter.PARAM_MIME_TYPE,
this.currentActionProperties.get(PROP_IMAGE_TRANSFORMER));
// add the options
actionParams.put(ImageTransformActionExecuter.PARAM_CONVERT_COMMAND,
this.currentActionProperties.get(PROP_TRANSFORM_OPTIONS));
// add the destination space id to the action properties
NodeRef destNodeRef = (NodeRef)this.currentActionProperties.get(PROP_DESTINATION);
actionParams.put(TransformActionExecuter.PARAM_DESTINATION_FOLDER, destNodeRef);
// add the type and name of the association to create when the copy
// is performed
actionParams.put(TransformActionExecuter.PARAM_ASSOC_TYPE_QNAME,
ContentModel.ASSOC_CONTAINS);
actionParams.put(TransformActionExecuter.PARAM_ASSOC_QNAME,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "copy"));
}
else if (this.action.equals(MailActionExecuter.NAME))
{
// add the actual email text to send
actionParams.put(MailActionExecuter.PARAM_TEXT,
this.currentActionProperties.get(PROP_MESSAGE));
// add the person it's going to
actionParams.put(MailActionExecuter.PARAM_TO,
this.currentActionProperties.get(PROP_TO));
// add the subject for the email
actionParams.put(MailActionExecuter.PARAM_SUBJECT,
this.currentActionProperties.get(PROP_SUBJECT));
}
else if (this.action.equals(ImporterActionExecuter.NAME))
{
// add the encoding
actionParams.put(ImporterActionExecuter.PARAM_ENCODING, IMPORT_ENCODING);
// add the destination for the import
NodeRef destNodeRef = (NodeRef)this.currentActionProperties.get(PROP_DESTINATION);
actionParams.put(ImporterActionExecuter.PARAM_DESTINATION_FOLDER, destNodeRef);
}
else if (this.action.equals(SpecialiseTypeActionExecuter.NAME) == true)
{
// add the specialisation type
String objectType = (String)this.currentActionProperties.get(PROP_OBJECT_TYPE);
actionParams.put(SpecialiseTypeActionExecuter.PARAM_TYPE_NAME, QName.createQName(objectType));
}
return actionParams;
}
/**
* Populate the actionProperties member variable with correct props for the current action
* using the supplied property map.
*
* @param actionProps Map to retrieve props appropriate to the current action from
*/
protected void populateActionFromProperties(Map<String, Serializable> actionProps)
{
if (this.action.equals(AddFeaturesActionExecuter.NAME))
{
QName aspect = (QName)actionProps.get(AddFeaturesActionExecuter.PARAM_ASPECT_NAME);
this.currentActionProperties.put(PROP_ASPECT, aspect.toString());
}
else if (this.action.equals(CopyActionExecuter.NAME))
{
NodeRef destNodeRef = (NodeRef)actionProps.get(CopyActionExecuter.PARAM_DESTINATION_FOLDER);
this.currentActionProperties.put(PROP_DESTINATION, destNodeRef);
}
else if (this.action.equals(MoveActionExecuter.NAME))
{
NodeRef destNodeRef = (NodeRef)actionProps.get(MoveActionExecuter.PARAM_DESTINATION_FOLDER);
this.currentActionProperties.put(PROP_DESTINATION, destNodeRef);
}
else if (this.action.equals(SimpleWorkflowActionExecuter.NAME))
{
String approveStep = (String)actionProps.get(SimpleWorkflowActionExecuter.PARAM_APPROVE_STEP);
Boolean approveMove = (Boolean)actionProps.get(SimpleWorkflowActionExecuter.PARAM_APPROVE_MOVE);
NodeRef approveFolderNode = (NodeRef)actionProps.get(
SimpleWorkflowActionExecuter.PARAM_APPROVE_FOLDER);
String rejectStep = (String)actionProps.get(SimpleWorkflowActionExecuter.PARAM_REJECT_STEP);
Boolean rejectMove = (Boolean)actionProps.get(SimpleWorkflowActionExecuter.PARAM_REJECT_MOVE);
NodeRef rejectFolderNode = (NodeRef)actionProps.get(
SimpleWorkflowActionExecuter.PARAM_REJECT_FOLDER);
this.currentActionProperties.put(PROP_APPROVE_STEP_NAME, approveStep);
this.currentActionProperties.put(PROP_APPROVE_ACTION, approveMove ? "move" : "copy");
this.currentActionProperties.put(PROP_APPROVE_FOLDER, approveFolderNode);
if (rejectStep == null && rejectMove == null && rejectFolderNode == null)
{
this.currentActionProperties.put(PROP_REJECT_STEP_PRESENT, "no");
}
else
{
this.currentActionProperties.put(PROP_REJECT_STEP_PRESENT, "yes");
this.currentActionProperties.put(PROP_REJECT_STEP_NAME, rejectStep);
this.currentActionProperties.put(PROP_REJECT_ACTION, rejectMove ? "move" : "copy");
this.currentActionProperties.put(PROP_REJECT_FOLDER, rejectFolderNode);
}
}
else if (this.action.equals(LinkCategoryActionExecuter.NAME))
{
NodeRef catNodeRef = (NodeRef)actionProps.get(LinkCategoryActionExecuter.PARAM_CATEGORY_VALUE);
this.currentActionProperties.put(PROP_CATEGORY, catNodeRef);
}
else if (this.action.equals(CheckOutActionExecuter.NAME))
{
NodeRef destNodeRef = (NodeRef)actionProps.get(CheckOutActionExecuter.PARAM_DESTINATION_FOLDER);
this.currentActionProperties.put(PROP_DESTINATION, destNodeRef);
}
else if (this.action.equals(CheckInActionExecuter.NAME))
{
String checkDesc = (String)actionProps.get(CheckInActionExecuter.PARAM_DESCRIPTION);
this.currentActionProperties.put(PROP_CHECKIN_DESC, checkDesc);
Boolean minorChange = (Boolean)actionProps.get(CheckInActionExecuter.PARAM_MINOR_CHANGE);
this.currentActionProperties.put(PROP_CHECKIN_MINOR, minorChange);
}
else if (this.action.equals(TransformActionExecuter.NAME))
{
String transformer = (String)actionProps.get(TransformActionExecuter.PARAM_MIME_TYPE);
this.currentActionProperties.put(PROP_TRANSFORMER, transformer);
NodeRef destNodeRef = (NodeRef)actionProps.get(CopyActionExecuter.PARAM_DESTINATION_FOLDER);
this.currentActionProperties.put(PROP_DESTINATION, destNodeRef);
}
else if (this.action.equals(ImageTransformActionExecuter.NAME))
{
String transformer = (String)actionProps.get(TransformActionExecuter.PARAM_MIME_TYPE);
this.currentActionProperties.put(PROP_IMAGE_TRANSFORMER, transformer);
String options = (String)actionProps.get(ImageTransformActionExecuter.PARAM_CONVERT_COMMAND);
this.currentActionProperties.put(PROP_TRANSFORM_OPTIONS, options != null ? options : "");
NodeRef destNodeRef = (NodeRef)actionProps.get(CopyActionExecuter.PARAM_DESTINATION_FOLDER);
this.currentActionProperties.put(PROP_DESTINATION, destNodeRef);
}
else if (this.action.equals(MailActionExecuter.NAME))
{
String subject = (String)actionProps.get(MailActionExecuter.PARAM_SUBJECT);
this.currentActionProperties.put(PROP_SUBJECT, subject);
String message = (String)actionProps.get(MailActionExecuter.PARAM_TEXT);
this.currentActionProperties.put(PROP_MESSAGE, message);
String to = (String)actionProps.get(MailActionExecuter.PARAM_TO);
this.currentActionProperties.put(PROP_TO, to);
}
else if (this.action.equals(ImporterActionExecuter.NAME))
{
NodeRef destNodeRef = (NodeRef)actionProps.get(ImporterActionExecuter.PARAM_DESTINATION_FOLDER);
this.currentActionProperties.put(PROP_DESTINATION, destNodeRef);
}
else if (this.action.equals(SpecialiseTypeActionExecuter.NAME) == true)
{
QName specialiseType = (QName)actionProps.get(SpecialiseTypeActionExecuter.PARAM_TYPE_NAME);
this.currentActionProperties.put(PROP_OBJECT_TYPE, specialiseType.toString());
}
}
/**
* @return Returns the selected action
*/
public String getAction()
{
return this.action;
}
/**
* @param action Sets the selected action
*/
public void setAction(String action)
{
this.action = action;
}
/**
* Sets the action service
*
* @param actionRegistration the action service
*/
public void setActionService(ActionService actionService)
{
this.actionService = actionService;
}
/**
* Sets the dictionary service
*
* @param dictionaryService the dictionary service
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* Sets the mimetype service
*
* @param mimetypeService The mimetype service
*/
public void setMimetypeService(MimetypeService mimetypeService)
{
this.mimetypeService = mimetypeService;
}
/**
* @return Returns the list of selectable actions
*/
public List<SelectItem> getActions()
{
if (this.actions == null)
{
List<ActionDefinition> ruleActions = this.actionService.getActionDefinitions();
this.actions = new ArrayList<SelectItem>();
for (ActionDefinition ruleActionDef : ruleActions)
{
this.actions.add(new SelectItem(ruleActionDef.getName(), ruleActionDef.getTitle()));
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(this.actions, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
return this.actions;
}
/**
* @return Returns a map of all the action descriptions
*/
public Map<String, String> getActionDescriptions()
{
if (this.actionDescriptions == null)
{
List<ActionDefinition> ruleActions = this.actionService.getActionDefinitions();
this.actionDescriptions = new HashMap<String, String>();
for (ActionDefinition ruleActionDef : ruleActions)
{
this.actionDescriptions.put(ruleActionDef.getName(), ruleActionDef.getDescription());
}
}
return this.actionDescriptions;
}
/**
* @return Gets the action settings
*/
public Map<String, Serializable> getActionProperties()
{
return this.currentActionProperties;
}
/**
* Returns a list of encodings the import and export actions can use
*
* @return List of SelectItem objects representing the available encodings
*/
public List<SelectItem> getEncodings()
{
if (this.encodings == null)
{
ConfigService svc = (ConfigService)FacesContextUtils.getRequiredWebApplicationContext(
FacesContext.getCurrentInstance()).getBean(Application.BEAN_CONFIG_SERVICE);
Config wizardCfg = svc.getConfig("Action Wizards");
if (wizardCfg != null)
{
ConfigElement encodingsCfg = wizardCfg.getConfigElement("encodings");
if (encodingsCfg != null)
{
FacesContext context = FacesContext.getCurrentInstance();
this.encodings = new ArrayList<SelectItem>();
for (ConfigElement child : encodingsCfg.getChildren())
{
String id = child.getAttribute("name");
// look for a client localized string
String label = null;
String msgId = child.getAttribute("displayLabelId");
if (msgId != null)
{
label = Application.getMessage(context, msgId);
}
// if there wasn't an externalized string look for one in the config
if (label == null)
{
label = child.getAttribute("displayLabel");
}
this.encodings.add(new SelectItem(id, label));
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(this.encodings, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
else
{
logger.warn("Could not find encodings configuration element");
}
}
else
{
logger.warn("Could not find Action Wizards configuration section");
}
}
return this.encodings;
}
/**
* Returns the transformers that are available
*
* @return List of SelectItem objects representing the available transformers
*/
public List<SelectItem> getTransformers()
{
if (this.transformers == null)
{
ConfigService svc = (ConfigService)FacesContextUtils.getRequiredWebApplicationContext(
FacesContext.getCurrentInstance()).getBean(Application.BEAN_CONFIG_SERVICE);
Config wizardCfg = svc.getConfig("Action Wizards");
if (wizardCfg != null)
{
ConfigElement transformersCfg = wizardCfg.getConfigElement("transformers");
if (transformersCfg != null)
{
FacesContext context = FacesContext.getCurrentInstance();
Map<String, String> mimeTypes = this.mimetypeService.getDisplaysByMimetype();
this.transformers = new ArrayList<SelectItem>();
for (ConfigElement child : transformersCfg.getChildren())
{
String id = child.getAttribute("name");
// look for a client localized string
String label = null;
String msgId = child.getAttribute("displayLabelId");
if (msgId != null)
{
label = Application.getMessage(context, msgId);
}
// if there wasn't an externalized string look for one in the config
if (label == null)
{
label = child.getAttribute("displayLabel");
}
// if there wasn't a client based label get it from the mime type service
if (label == null)
{
label = mimeTypes.get(id);
}
this.transformers.add(new SelectItem(id, label));
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(this.transformers, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
else
{
logger.warn("Could not find transformers configuration element");
}
}
else
{
logger.warn("Could not find Action Wizards configuration section");
}
}
return this.transformers;
}
/**
* Returns the image transformers that are available
*
* @return List of SelectItem objects representing the available image transformers
*/
public List<SelectItem> getImageTransformers()
{
if (this.imageTransformers == null)
{
ConfigService svc = (ConfigService)FacesContextUtils.getRequiredWebApplicationContext(
FacesContext.getCurrentInstance()).getBean(Application.BEAN_CONFIG_SERVICE);
Config wizardCfg = svc.getConfig("Action Wizards");
if (wizardCfg != null)
{
ConfigElement transformersCfg = wizardCfg.getConfigElement("image-transformers");
if (transformersCfg != null)
{
FacesContext context = FacesContext.getCurrentInstance();
Map<String, String> mimeTypes = this.mimetypeService.getDisplaysByMimetype();
this.imageTransformers = new ArrayList<SelectItem>();
for (ConfigElement child : transformersCfg.getChildren())
{
String id = child.getAttribute("name");
// look for a client localized string
String label = null;
String msgId = child.getAttribute("displayLabelId");
if (msgId != null)
{
label = Application.getMessage(context, msgId);
}
// if there wasn't an externalized string look for one in the config
if (label == null)
{
label = child.getAttribute("displayLabel");
}
// if there wasn't a client based label get it from the mime type service
if (label == null)
{
label = mimeTypes.get(id);
}
this.imageTransformers.add(new SelectItem(id, label));
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(this.imageTransformers, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
else
{
logger.warn("Could not find image-transformers configuration element");
}
}
else
{
logger.warn("Could not find Action Wizards configuration section");
}
}
return this.imageTransformers;
}
/**
* Returns the aspects that are available
*
* @return List of SelectItem objects representing the available aspects
*/
public List<SelectItem> getAspects()
{
if (this.aspects == null)
{
ConfigService svc = (ConfigService)FacesContextUtils.getRequiredWebApplicationContext(
FacesContext.getCurrentInstance()).getBean(Application.BEAN_CONFIG_SERVICE);
Config wizardCfg = svc.getConfig("Action Wizards");
if (wizardCfg != null)
{
ConfigElement aspectsCfg = wizardCfg.getConfigElement("aspects");
if (aspectsCfg != null)
{
FacesContext context = FacesContext.getCurrentInstance();
this.aspects = new ArrayList<SelectItem>();
for (ConfigElement child : aspectsCfg.getChildren())
{
QName idQName = Repository.resolveToQName(child.getAttribute("name"));
// look for a client localized string
String label = null;
String msgId = child.getAttribute("displayLabelId");
if (msgId != null)
{
label = Application.getMessage(context, msgId);
}
// if there wasn't an externalized string look for one in the config
if (label == null)
{
label = child.getAttribute("displayLabel");
}
// if there wasn't a client based label try and get it from the dictionary
if (label == null)
{
AspectDefinition aspectDef = this.dictionaryService.getAspect(idQName);
if (aspectDef != null)
{
label = aspectDef.getTitle();
}
else
{
label = idQName.getLocalName();
}
}
this.aspects.add(new SelectItem(idQName.toString(), label));
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(this.aspects, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
else
{
logger.warn("Could not find aspects configuration element");
}
}
else
{
logger.warn("Could not find Action Wizards configuration section");
}
}
return this.aspects;
}
/**
* @return Returns a list of object types to allow the user to select from
*/
public List<SelectItem> getObjectTypes()
{
if (this.objectTypes == null)
{
FacesContext context = FacesContext.getCurrentInstance();
// add the well known object type to start with
this.objectTypes = new ArrayList<SelectItem>(5);
this.objectTypes.add(new SelectItem(ContentModel.TYPE_CONTENT.toString(),
Application.getMessage(context, "content")));
// add any configured content sub-types to the list
ConfigService svc = (ConfigService)FacesContextUtils.getRequiredWebApplicationContext(
FacesContext.getCurrentInstance()).getBean(Application.BEAN_CONFIG_SERVICE);
Config wizardCfg = svc.getConfig("Custom Content Types");
if (wizardCfg != null)
{
ConfigElement typesCfg = wizardCfg.getConfigElement("content-types");
if (typesCfg != null)
{
for (ConfigElement child : typesCfg.getChildren())
{
QName idQName = Repository.resolveToQName(child.getAttribute("name"));
TypeDefinition typeDef = this.dictionaryService.getType(idQName);
if (typeDef != null &&
this.dictionaryService.isSubClass(typeDef.getName(), ContentModel.TYPE_CONTENT))
{
// look for a client localized string
String label = null;
String msgId = child.getAttribute("displayLabelId");
if (msgId != null)
{
label = Application.getMessage(context, msgId);
}
// if there wasn't an externalized string look for one in the config
if (label == null)
{
label = child.getAttribute("displayLabel");
}
// if there wasn't a client based label try and get it from the dictionary
if (label == null)
{
label = typeDef.getTitle();
}
// finally, just use the localname
if (label == null)
{
label = idQName.getLocalName();
}
this.objectTypes.add(new SelectItem(idQName.toString(), label));
}
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(this.objectTypes, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
else
{
logger.warn("Could not find 'content-types' configuration element");
}
}
else
{
logger.warn("Could not find 'Custom Content Types' configuration section");
}
}
return this.objectTypes;
}
/**
* @return the List of users in the system wrapped in SelectItem objects
*/
public List<SelectItem> getUsers()
{
if (this.users == null)
{
List<Node> userNodes = Repository.getUsers(
FacesContext.getCurrentInstance(),
this.nodeService,
this.searchService);
this.users = new ArrayList<SelectItem>();
for (Node user : userNodes)
{
String email = (String)user.getProperties().get("email");
if (email != null && email.length() > 0)
{
this.users.add(new SelectItem(email, (String)user.getProperties().get("fullName")));
}
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(this.users, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
return this.users;
}
}

View File

@@ -0,0 +1,611 @@
/*
* 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.web.bean.wizard;
import java.io.File;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import javax.transaction.UserTransaction;
import org.alfresco.config.Config;
import org.alfresco.config.ConfigElement;
import org.alfresco.config.ConfigService;
import org.alfresco.model.ContentModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
import org.alfresco.web.ui.common.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.jsf.FacesContextUtils;
/**
* Base Handler class used by the Content Wizards
*
* @author gavinc kevinr
*/
public abstract class BaseContentWizard extends AbstractWizardBean
{
private static Log logger = LogFactory.getLog(BaseContentWizard.class);
protected static final String FINISH_INSTRUCTION_ID = "content_finish_instruction";
// content wizard specific attributes
protected String fileName;
protected String author;
protected String title;
protected String description;
protected String contentType;
protected String objectType;
protected boolean inlineEdit;
protected List<SelectItem> contentTypes;
protected List<SelectItem> objectTypes;
protected ContentService contentService;
protected DictionaryService dictionaryService;
// the NodeRef of the node created during finish
protected NodeRef createdNode;
/**
* Save the specified content using the currently set wizard attributes
*
* @param fileContent File content to save
* @param strContent String content to save
*/
protected String saveContent(File fileContent, String strContent)
{
String outcome = FINISH_OUTCOME;
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
if (this.editMode)
{
// update the existing node in the repository
Node currentDocument = this.browseBean.getDocument();
NodeRef nodeRef = currentDocument.getNodeRef();
// move the file - location and name checks will be performed
this.fileFolderService.move(nodeRef, null, this.fileName);
// set up the content data
// update the modified timestamp and other content props
Map<QName, Serializable> contentProps = this.nodeService.getProperties(nodeRef);
contentProps.put(ContentModel.PROP_TITLE, this.title);
contentProps.put(ContentModel.PROP_DESCRIPTION, this.description);
contentProps.put(ContentModel.PROP_CREATOR, this.author);
// set up content properties - copy or create the compound property
ContentData contentData = (ContentData)contentProps.get(ContentModel.PROP_CONTENT);
if (contentData == null)
{
contentData = new ContentData(null, this.contentType, 0L, "UTF-8");
}
else
{
contentData = new ContentData(
contentData.getContentUrl(),
this.contentType,
contentData.getSize(),
contentData.getEncoding());
}
contentProps.put(ContentModel.PROP_CONTENT, contentData);
if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_INLINEEDITABLE) == false)
{
Map<QName, Serializable> editProps = new HashMap<QName, Serializable>(1, 1.0f);
editProps.put(ContentModel.PROP_EDITINLINE, this.inlineEdit);
this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_INLINEEDITABLE, editProps);
}
else
{
contentProps.put(ContentModel.PROP_EDITINLINE, this.inlineEdit);
}
this.nodeService.setProperties(nodeRef, contentProps);
}
else
{
// get the node ref of the node that will contain the content
NodeRef containerNodeRef;
String nodeId = getNavigator().getCurrentNodeId();
if (nodeId == null)
{
containerNodeRef = this.nodeService.getRootNode(Repository.getStoreRef());
}
else
{
containerNodeRef = new NodeRef(Repository.getStoreRef(), nodeId);
}
FileInfo fileInfo = fileFolderService.create(
containerNodeRef,
this.fileName,
Repository.resolveToQName(this.objectType));
NodeRef fileNodeRef = fileInfo.getNodeRef();
// set the author (if we have)
if (this.author != null && this.author.length() > 0)
{
this.nodeService.setProperty(fileNodeRef, ContentModel.PROP_CREATOR, this.author);
}
if (logger.isDebugEnabled())
logger.debug("Created file node for file: " + this.fileName);
// apply the titled aspect - title and description
Map<QName, Serializable> titledProps = new HashMap<QName, Serializable>(3, 1.0f);
titledProps.put(ContentModel.PROP_TITLE, this.title);
titledProps.put(ContentModel.PROP_DESCRIPTION, this.description);
this.nodeService.addAspect(fileNodeRef, ContentModel.ASPECT_TITLED, titledProps);
if (logger.isDebugEnabled())
logger.debug("Added titled aspect with properties: " + titledProps);
// apply the inlineeditable aspect
if (this.inlineEdit == true)
{
Map<QName, Serializable> editProps = new HashMap<QName, Serializable>(1, 1.0f);
editProps.put(ContentModel.PROP_EDITINLINE, this.inlineEdit);
this.nodeService.addAspect(fileNodeRef, ContentModel.ASPECT_INLINEEDITABLE, editProps);
if (logger.isDebugEnabled())
logger.debug("Added inlineeditable aspect with properties: " + editProps);
}
// get a writer for the content and put the file
ContentWriter writer = contentService.getWriter(fileNodeRef, ContentModel.PROP_CONTENT, true);
// set the mimetype and encoding
writer.setMimetype(this.contentType);
writer.setEncoding("UTF-8");
if (fileContent != null)
{
writer.putContent(fileContent);
}
else if (strContent != null)
{
writer.putContent(strContent);
}
// remember the created node now
this.createdNode = fileNodeRef;
}
// give subclasses a chance to perform custom processing before committing
performCustomProcessing();
// commit the transaction
tx.commit();
}
catch (FileExistsException e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
// print status message
String statusMsg = MessageFormat.format(
Application.getMessage(
FacesContext.getCurrentInstance(), "error_exists"),
e.getExisting().getName());
Utils.addErrorMessage(statusMsg);
// no outcome
outcome = null;
}
catch (Exception e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), e.getMessage()), e);
outcome = null;
}
return outcome;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepInstructions()
*/
public String getStepInstructions()
{
String stepInstruction = null;
switch (this.currentStep)
{
case 3:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), FINISH_INSTRUCTION_ID);
break;
}
default:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), DEFAULT_INSTRUCTION_ID);
}
}
return stepInstruction;
}
/**
* Initialises the wizard
*/
public void init()
{
super.init();
this.fileName = null;
this.author = null;
this.title = null;
this.description = null;
this.contentType = null;
this.inlineEdit = false;
this.contentTypes = null;
this.objectTypes = null;
this.objectType = ContentModel.TYPE_CONTENT.toString();
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#populate()
*/
public void populate()
{
// get hold of the current document and populate the appropriate values
Node currentDocument = this.browseBean.getDocument();
Map<String, Object> props = currentDocument.getProperties();
Boolean inline = (Boolean)props.get("editInline");
this.inlineEdit = inline != null ? inline.booleanValue() : false;
this.author = (String)props.get("creator");
this.contentType = null;
ContentData contentData = (ContentData)props.get(ContentModel.PROP_CONTENT);
if (contentData != null)
{
this.contentType = contentData.getMimetype();
}
this.description = (String)props.get("description");
this.fileName = currentDocument.getName();
this.title = (String)props.get("title");
}
/**
* @return Returns the contentService.
*/
public ContentService getContentService()
{
return contentService;
}
/**
* @param contentService The contentService to set.
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* Sets the dictionary service
*
* @param dictionaryService the dictionary service
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* @return Returns the name of the file
*/
public String getFileName()
{
return this.fileName;
}
/**
* @param fileName The name of the file
*/
public void setFileName(String fileName)
{
this.fileName = fileName;
}
/**
* @return Returns the author
*/
public String getAuthor()
{
return this.author;
}
/**
* @param author Sets the author
*/
public void setAuthor(String author)
{
this.author = author;
}
/**
* @return Returns the content type currenty selected
*/
public String getContentType()
{
return this.contentType;
}
/**
* @param contentType Sets the currently selected content type
*/
public void setContentType(String contentType)
{
this.contentType = contentType;
}
/**
* @return Returns the object type currenty selected
*/
public String getObjectType()
{
return this.objectType;
}
/**
* @param objectType Sets the currently selected object type
*/
public void setObjectType(String objectType)
{
this.objectType = objectType;
}
/**
* @return Returns the description
*/
public String getDescription()
{
return this.description;
}
/**
* @param description Sets the description
*/
public void setDescription(String description)
{
this.description = description;
}
/**
* @return Returns the title
*/
public String getTitle()
{
return this.title;
}
/**
* @param title Sets the title
*/
public void setTitle(String title)
{
this.title = title;
}
/**
* @return Returns the inline edit flag.
*/
public boolean isInlineEdit()
{
return this.inlineEdit;
}
/**
* @param inlineEdit The inline edit flag to set.
*/
public void setInlineEdit(boolean inlineEdit)
{
this.inlineEdit = inlineEdit;
}
/**
* @return Returns a list of content types to allow the user to select from
*/
public List<SelectItem> getContentTypes()
{
if (this.contentTypes == null)
{
this.contentTypes = new ArrayList<SelectItem>(80);
ServiceRegistry registry = Repository.getServiceRegistry(FacesContext.getCurrentInstance());
MimetypeService mimetypeService = registry.getMimetypeService();
// get the mime type display names
Map<String, String> mimeTypes = mimetypeService.getDisplaysByMimetype();
for (String mimeType : mimeTypes.keySet())
{
this.contentTypes.add(new SelectItem(mimeType, mimeTypes.get(mimeType)));
}
// make sure the list is sorted by the values
QuickSort sorter = new QuickSort(this.contentTypes, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
return this.contentTypes;
}
/**
* @return Returns a list of object types to allow the user to select from
*/
public List<SelectItem> getObjectTypes()
{
if (this.objectTypes == null)
{
FacesContext context = FacesContext.getCurrentInstance();
// add the well known object type to start with
this.objectTypes = new ArrayList<SelectItem>(5);
this.objectTypes.add(new SelectItem(ContentModel.TYPE_CONTENT.toString(),
Application.getMessage(context, "content")));
// add any configured content sub-types to the list
ConfigService svc = (ConfigService)FacesContextUtils.getRequiredWebApplicationContext(
FacesContext.getCurrentInstance()).getBean(Application.BEAN_CONFIG_SERVICE);
Config wizardCfg = svc.getConfig("Custom Content Types");
if (wizardCfg != null)
{
ConfigElement typesCfg = wizardCfg.getConfigElement("content-types");
if (typesCfg != null)
{
for (ConfigElement child : typesCfg.getChildren())
{
QName idQName = Repository.resolveToQName(child.getAttribute("name"));
TypeDefinition typeDef = this.dictionaryService.getType(idQName);
if (typeDef != null &&
this.dictionaryService.isSubClass(typeDef.getName(), ContentModel.TYPE_CONTENT))
{
// look for a client localized string
String label = null;
String msgId = child.getAttribute("displayLabelId");
if (msgId != null)
{
label = Application.getMessage(context, msgId);
}
// if there wasn't an externalized string look for one in the config
if (label == null)
{
label = child.getAttribute("displayLabel");
}
// if there wasn't a client based label try and get it from the dictionary
if (label == null)
{
label = typeDef.getTitle();
}
// finally, just use the localname
if (label == null)
{
label = idQName.getLocalName();
}
this.objectTypes.add(new SelectItem(idQName.toString(), label));
}
}
// make sure the list is sorted by the label
QuickSort sorter = new QuickSort(this.objectTypes, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
}
else
{
logger.warn("Could not find 'content-types' configuration element");
}
}
else
{
logger.warn("Could not find 'Custom Content Types' configuration section");
}
}
return this.objectTypes;
}
/**
* @return Determines whether the next and finish button should be enabled
*/
public boolean getNextFinishDisabled()
{
boolean disabled = false;
if (this.fileName == null || this.fileName.length() == 0 ||
this.title == null || this.title.length() == 0 ||
this.contentType == null)
{
disabled = true;
}
return disabled;
}
/**
* Returns the display label for the content type currently chosen
*
* @return The human readable version of the content type
*/
protected String getSummaryContentType()
{
ServiceRegistry registry = Repository.getServiceRegistry(FacesContext.getCurrentInstance());
MimetypeService mimetypeService = registry.getMimetypeService();
// get the mime type display name
Map<String, String> mimeTypes = mimetypeService.getDisplaysByMimetype();
return mimeTypes.get(this.contentType);
}
/**
* Returns the display label for the currently selected object type
*
* @return The objevt type label
*/
protected String getSummaryObjectType()
{
String objType = null;
for (SelectItem item : this.getObjectTypes())
{
if (item.getValue().equals(this.objectType))
{
objType = item.getLabel();
break;
}
}
return objType;
}
/**
* Performs any processing sub classes may wish to do before commit is called
*/
protected void performCustomProcessing()
{
// used by subclasses if necessary
}
}

View File

@@ -0,0 +1,300 @@
/*
* 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.web.bean.wizard;
import java.util.ResourceBundle;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Handler class used by the Create In-line Content Wizard
*
* @author Kevin Roast
*/
public class CreateContentWizard extends BaseContentWizard
{
protected static final String CONTENT_TEXT = "txt";
protected static final String CONTENT_HTML = "html";
private static Log logger = LogFactory.getLog(CreateContentWizard.class);
// TODO: retrieve these from the config service
private static final String WIZARD_TITLE_ID = "create_content_title";
private static final String WIZARD_DESC_ID = "create_content_desc";
private static final String STEP1_TITLE_ID = "create_content_step1_title";
private static final String STEP1_DESCRIPTION_ID = "create_content_step1_desc";
private static final String STEP2_TITLE_ID = "create_content_step2_title";
private static final String STEP2_DESCRIPTION_ID = "create_content_step2_desc";
private static final String STEP3_TITLE_ID = "create_content_step3_title";
private static final String STEP3_DESCRIPTION_ID = "create_content_step3_desc";
// create content wizard specific properties
protected String content;
protected String createType = CONTENT_HTML;
/**
* Deals with the finish button being pressed
*
* @return outcome
*/
public String finish()
{
return saveContent(null, this.content);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardDescription()
*/
public String getWizardDescription()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_DESC_ID);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardTitle()
*/
public String getWizardTitle()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_TITLE_ID);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepDescription()
*/
public String getStepDescription()
{
String stepDesc = null;
switch (this.currentStep)
{
case 1:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), STEP1_DESCRIPTION_ID);
break;
}
case 2:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), STEP2_DESCRIPTION_ID);
break;
}
case 3:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), STEP3_DESCRIPTION_ID);
break;
}
case 4:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), SUMMARY_DESCRIPTION_ID);
break;
}
default:
{
stepDesc = "";
}
}
return stepDesc;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepInstructions()
*/
public String getStepInstructions()
{
String stepInstruction = null;
switch (this.currentStep)
{
case 4:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), FINISH_INSTRUCTION_ID);
break;
}
default:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), DEFAULT_INSTRUCTION_ID);
}
}
return stepInstruction;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepTitle()
*/
public String getStepTitle()
{
String stepTitle = null;
switch (this.currentStep)
{
case 1:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP1_TITLE_ID);
break;
}
case 2:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP2_TITLE_ID);
break;
}
case 3:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP3_TITLE_ID);
break;
}
case 4:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), SUMMARY_TITLE_ID);
break;
}
default:
{
stepTitle = "";
}
}
return stepTitle;
}
/**
* @return Returns the content from the edited form.
*/
public String getContent()
{
return this.content;
}
/**
* @param content The content to edit (should be clear initially)
*/
public void setContent(String content)
{
this.content = content;
}
/**
* Initialises the wizard
*/
public void init()
{
super.init();
this.content = null;
// created content is inline editable by default
this.inlineEdit = true;
}
/**
* @return Returns the summary data for the wizard.
*/
public String getSummary()
{
ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance());
// TODO: show first few lines of content here?
return buildSummary(
new String[] {bundle.getString("file_name"), bundle.getString("type"),
bundle.getString("content_type"), bundle.getString("title"),
bundle.getString("description"), bundle.getString("author")},
new String[] {this.fileName, getSummaryObjectType(), getSummaryContentType(),
this.title, this.description, this.author});
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#determineOutcomeForStep(int)
*/
protected String determineOutcomeForStep(int step)
{
String outcome = null;
switch(step)
{
case 1:
{
outcome = "select";
break;
}
case 2:
{
if (getCreateType().equals(CONTENT_HTML))
{
outcome = "create-html";
}
else if (getCreateType().equals(CONTENT_TEXT))
{
outcome = "create-text";
}
break;
}
case 3:
{
this.fileName = "newfile." + getCreateType();
this.contentType = Repository.getMimeTypeForFileName(
FacesContext.getCurrentInstance(), this.fileName);
this.title = this.fileName;
outcome = "properties";
break;
}
case 4:
{
outcome = "summary";
break;
}
default:
{
outcome = CANCEL_OUTCOME;
}
}
return outcome;
}
/**
* Create content type value changed by the user
*/
public void createContentChanged(ValueChangeEvent event)
{
// clear the content as HTML is not compatible with the plain text box etc.
this.content = null;
}
/**
* @return Returns the createType.
*/
public String getCreateType()
{
return this.createType;
}
/**
* @param createType The createType to set.
*/
public void setCreateType(String createType)
{
this.createType = createType;
}
}

View File

@@ -0,0 +1,806 @@
/*
* 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.web.bean.wizard;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Set;
import javax.faces.component.UISelectOne;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.ui.common.SortableSelectItem;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIGenericPicker;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
/**
* @author Kevin Roast
*/
public class InviteUsersWizard extends AbstractWizardBean
{
private static Log logger = LogFactory.getLog(InviteUsersWizard.class);
/** I18N message strings */
private static final String MSG_USERS = "users";
private static final String MSG_GROUPS = "groups";
private static final String MSG_INVITED_SPACE = "invite_space";
private static final String MSG_INVITED_ROLE = "invite_role";
private static final String WIZARD_TITLE_ID = "invite_title";
private static final String WIZARD_DESC_ID = "invite_desc";
private static final String STEP1_TITLE_ID = "invite_step1_title";
private static final String STEP1_DESCRIPTION_ID = "invite_step1_desc";
private static final String STEP2_TITLE_ID = "invite_step2_title";
private static final String STEP2_DESCRIPTION_ID = "invite_step2_desc";
private static final String FINISH_INSTRUCTION_ID = "invite_finish_instruction";
private static final String NOTIFY_YES = "yes";
/** NamespaceService bean reference */
private NamespaceService namespaceService;
/** JavaMailSender bean reference */
private JavaMailSender mailSender;
/** AuthorityService bean reference */
private AuthorityService authorityService;
/** PermissionService bean reference */
private PermissionService permissionService;
/** personService bean reference */
private PersonService personService;
/** datamodel for table of roles for users */
private DataModel userRolesDataModel = null;
/** list of user/group role wrapper objects */
private List<UserGroupRole> userGroupRoles = null;
/** Cache of available folder permissions */
Set<String> folderPermissions = null;
/** dialog state */
private String notify = NOTIFY_YES;
private String subject = null;
private String body = null;
private String internalSubject = null;
private String automaticText = null;
/**
* @param namespaceService The NamespaceService to set.
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param mailSender The JavaMailSender to set.
*/
public void setMailSender(JavaMailSender mailSender)
{
this.mailSender = mailSender;
}
/**
* @param permissionService The PermissionService to set.
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* @param permissionService The PermissionService to set.
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
/**
* @param authorityService The authorityService to set.
*/
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
/**
* Initialises the wizard
*/
public void init()
{
super.init();
notify = NOTIFY_YES;
userGroupRoles = new ArrayList<UserGroupRole>(8);
subject = "";
body = "";
automaticText = "";
internalSubject = null;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#finish()
*/
public String finish()
{
String outcome = FINISH_OUTCOME;
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
String subject = this.subject;
if (subject == null || subject.length() == 0)
{
subject = this.internalSubject;
}
User user = Application.getCurrentUser(context);
String from = (String)this.nodeService.getProperty(user.getPerson(), ContentModel.PROP_EMAIL);
if (from == null || from.length() == 0)
{
// TODO: get this from spring config?
from = "alfresco@alfresco.org";
}
// get the Space to apply changes too
NodeRef folderNodeRef = this.browseBean.getActionSpace().getNodeRef();
// set permissions for each user and send them a mail
for (int i=0; i<this.userGroupRoles.size(); i++)
{
UserGroupRole userGroupRole = this.userGroupRoles.get(i);
String authority = userGroupRole.getAuthority();
// find the selected permission ref from it's name and apply for the specified user
Set<String> perms = getFolderPermissions();
for (String permission : perms)
{
if (userGroupRole.getRole().equals(permission))
{
this.permissionService.setPermission(
folderNodeRef,
authority,
permission,
true);
break;
}
}
// Create the mail message for sending to each User
if (NOTIFY_YES.equals(this.notify))
{
// if User, email then, else if Group get all members and email them
AuthorityType authType = AuthorityType.getAuthorityType(authority);
if (authType.equals(AuthorityType.USER))
{
if (this.personService.personExists(authority) == true)
{
notifyUser(this.personService.getPerson(authority), folderNodeRef, from, userGroupRole.getRole());
}
}
else if (authType.equals(AuthorityType.GROUP))
{
// else notify all members of the group
Set<String> users = this.authorityService.getContainedAuthorities(AuthorityType.USER, authority, false);
for (String userAuth : users)
{
if (this.personService.personExists(userAuth) == true)
{
notifyUser(this.personService.getPerson(userAuth), folderNodeRef, from, userGroupRole.getRole());
}
}
}
}
}
// commit the transaction
tx.commit();
UIContextService.getInstance(context).notifyBeans();
}
catch (Exception e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), e.getMessage()), e);
outcome = null;
}
return outcome;
}
/**
* Send an email notification to the specified User authority
*
* @param person Person node representing the user
* @param folder Folder node they are invited too
* @param from From text message
* @param roleText The role display label for the user invite notification
*/
private void notifyUser(NodeRef person, NodeRef folder, String from, String roleText)
{
String to = (String)this.nodeService.getProperty(person, ContentModel.PROP_EMAIL);
if (to != null && to.length() != 0)
{
String msgRole = Application.getMessage(FacesContext.getCurrentInstance(), MSG_INVITED_ROLE);
String roleMessage = MessageFormat.format(msgRole, new Object[] {roleText});
// TODO: include External Authentication link to the invited space
//String args = folder.getStoreRef().getProtocol() + '/' +
// folder.getStoreRef().getIdentifier() + '/' +
// folder.getId();
//String url = ExternalAccessServlet.generateExternalURL(LoginBean.OUTCOME_SPACEDETAILS, args);
String body = this.internalSubject + "\r\n\r\n" + roleMessage + "\r\n\r\n";// + url + "\r\n\r\n";
if (this.body != null && this.body.length() != 0)
{
body += this.body;
}
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setTo(to);
simpleMailMessage.setSubject(subject);
simpleMailMessage.setText(body);
simpleMailMessage.setFrom(from);
if (logger.isDebugEnabled())
logger.debug("Sending notification email to: " + to + "\n...with subject:\n" + subject + "\n...with body:\n" + body);
try
{
// Send the message
this.mailSender.send(simpleMailMessage);
}
catch (Throwable e)
{
// don't stop the action but let admins know email is not getting sent
logger.error("Failed to send email to " + to, e);
}
}
}
/**
* Returns the properties for current user-roles JSF DataModel
*
* @return JSF DataModel representing the current user-roles
*/
public DataModel getUserRolesDataModel()
{
if (this.userRolesDataModel == null)
{
this.userRolesDataModel = new ListDataModel();
}
this.userRolesDataModel.setWrappedData(this.userGroupRoles);
return this.userRolesDataModel;
}
/**
* Query callback method executed by the Generic Picker component.
* This method is part of the contract to the Generic Picker, it is up to the backing bean
* to execute whatever query is appropriate and return the results.
*
* @param filterIndex Index of the filter drop-down selection
* @param contains Text from the contains textbox
*
* @return An array of SelectItem objects containing the results to display in the picker.
*/
public SelectItem[] pickerCallback(int filterIndex, String contains)
{
FacesContext context = FacesContext.getCurrentInstance();
SelectItem[] items;
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(context, true);
tx.begin();
if (filterIndex == 0)
{
// build xpath to match available User/Person objects
NodeRef peopleRef = personService.getPeopleContainer();
// NOTE: see SearcherComponentTest
String xpath = "*[like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "firstName, '%" + contains + "%', false)" +
" or " + "like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "lastName, '%" + contains + "%', false)]";
List<NodeRef> nodes = searchService.selectNodes(
peopleRef,
xpath,
null,
this.namespaceService,
false);
items = new SelectItem[nodes.size()];
for (int index=0; index<nodes.size(); index++)
{
NodeRef personRef = nodes.get(index);
String firstName = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_FIRSTNAME);
String lastName = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_LASTNAME);
String username = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_USERNAME);
SelectItem item = new SortableSelectItem(username, firstName + " " + lastName, lastName);
items[index] = item;
}
}
else
{
// groups - simple text based match on name
Set<String> groups = authorityService.getAllAuthorities(AuthorityType.GROUP);
groups.addAll(authorityService.getAllAuthorities(AuthorityType.EVERYONE));
List<SelectItem> results = new ArrayList<SelectItem>(groups.size());
String containsLower = contains.toLowerCase();
int offset = PermissionService.GROUP_PREFIX.length();
for (String group : groups)
{
if (group.toLowerCase().indexOf(containsLower) != -1)
{
results.add(new SortableSelectItem(group, group.substring(offset), group));
}
}
items = new SelectItem[results.size()];
results.toArray(items);
}
Arrays.sort(items);
// commit the transaction
tx.commit();
}
catch (Exception err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err );
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
items = new SelectItem[0];
}
return items;
}
/**
* Action handler called when the Add button is pressed to process the current selection
*/
public void addSelection(ActionEvent event)
{
UIGenericPicker picker = (UIGenericPicker)event.getComponent().findComponent("picker");
UISelectOne rolePicker = (UISelectOne)event.getComponent().findComponent("roles");
String[] results = picker.getSelectedResults();
if (results != null)
{
String role = (String)rolePicker.getValue();
if (role != null)
{
for (int i=0; i<results.length; i++)
{
String authority = results[i];
// only add if authority not already present in the list with same role
boolean foundExisting = false;
for (int n=0; n<this.userGroupRoles.size(); n++)
{
UserGroupRole wrapper = this.userGroupRoles.get(n);
if (authority.equals(wrapper.getAuthority()) &&
role.equals(wrapper.getRole()))
{
foundExisting = true;
break;
}
}
if (foundExisting == false)
{
StringBuilder label = new StringBuilder(64);
// build a display label showing the user and their role for the space
AuthorityType authType = AuthorityType.getAuthorityType(authority);
if (authType.equals(AuthorityType.USER))
{
if (this.personService.personExists(authority) == true)
{
// found a User authority
NodeRef ref = this.personService.getPerson(authority);
String firstName = (String)this.nodeService.getProperty(ref, ContentModel.PROP_FIRSTNAME);
String lastName = (String)this.nodeService.getProperty(ref, ContentModel.PROP_LASTNAME);
label.append(firstName)
.append(" ")
.append(lastName)
.append(" (")
.append(Application.getMessage(FacesContext.getCurrentInstance(), role))
.append(")");
}
}
else
{
// found a group authority
label.append(authority.substring(PermissionService.GROUP_PREFIX.length()));
}
this.userGroupRoles.add(new UserGroupRole(authority, role, label.toString()));
}
}
}
}
}
/**
* Action handler called when the Remove button is pressed to remove a user+role
*/
public void removeSelection(ActionEvent event)
{
UserGroupRole wrapper = (UserGroupRole)this.userRolesDataModel.getRowData();
if (wrapper != null)
{
this.userGroupRoles.remove(wrapper);
}
}
/**
* Property accessed by the Generic Picker component.
*
* @return the array of filter options to show in the users/groups picker
*/
public SelectItem[] getFilters()
{
ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance());
return new SelectItem[] {
new SelectItem("0", bundle.getString(MSG_USERS)),
new SelectItem("1", bundle.getString(MSG_GROUPS)) };
}
/**
* @return The list of available roles for the users/groups
*/
public SelectItem[] getRoles()
{
ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance());
// get available roles (grouped permissions) from the permission service
Set<String> perms = getFolderPermissions();
SelectItem[] roles = new SelectItem[perms.size()];
int index = 0;
for (String permission : perms)
{
String displayLabel = bundle.getString(permission);
roles[index++] = new SelectItem(permission, displayLabel);
}
return roles;
}
/**
* @return Returns the notify listbox selection.
*/
public String getNotify()
{
return this.notify;
}
/**
* @param notify The notify listbox selection to set.
*/
public void setNotify(String notify)
{
this.notify = notify;
}
/**
* @return Returns the automaticText.
*/
public String getAutomaticText()
{
return this.automaticText;
}
/**
* @param automaticText The automaticText to set.
*/
public void setAutomaticText(String automaticText)
{
this.automaticText = automaticText;
}
/**
* @return Returns the email body text.
*/
public String getBody()
{
return this.body;
}
/**
* @param body The email body text to set.
*/
public void setBody(String body)
{
this.body = body;
}
/**
* @return Returns the email subject text.
*/
public String getSubject()
{
return this.subject;
}
/**
* @param subject The email subject text to set.
*/
public void setSubject(String subject)
{
this.subject = subject;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardDescription()
*/
public String getWizardDescription()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_DESC_ID);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardTitle()
*/
public String getWizardTitle()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_TITLE_ID);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepDescription()
*/
public String getStepDescription()
{
String stepDesc = null;
switch (this.currentStep)
{
case 1:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), STEP1_DESCRIPTION_ID);
break;
}
case 2:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), STEP2_DESCRIPTION_ID);
break;
}
default:
{
stepDesc = "";
}
}
return stepDesc;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepTitle()
*/
public String getStepTitle()
{
String stepTitle = null;
switch (this.currentStep)
{
case 1:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP1_TITLE_ID);
break;
}
case 2:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP2_TITLE_ID);
break;
}
default:
{
stepTitle = "";
}
}
return stepTitle;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepInstructions()
*/
public String getStepInstructions()
{
String stepInstruction = null;
switch (this.currentStep)
{
case 2:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), FINISH_INSTRUCTION_ID);
break;
}
default:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), DEFAULT_INSTRUCTION_ID);
}
}
return stepInstruction;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#next()
*/
public String next()
{
String outcome = super.next();
if (outcome.equals("notify"))
{
FacesContext context = FacesContext.getCurrentInstance();
// prepare automatic text for email and screen
StringBuilder buf = new StringBuilder(256);
String personName = Application.getCurrentUser(context).getFullName(getNodeService());
String msgInvite = Application.getMessage(context, MSG_INVITED_SPACE);
Node node = this.browseBean.getActionSpace();
String path = this.nodeService.getPath(node.getNodeRef()).toDisplayPath(this.nodeService);
buf.append(MessageFormat.format(msgInvite, new Object[] {
path + '/' + node.getName(),
personName}) );
this.internalSubject = buf.toString();
buf.append("<br>");
String msgRole = Application.getMessage(context, MSG_INVITED_ROLE);
String roleText;
if (this.userGroupRoles.size() != 0)
{
String roleMsg = Application.getMessage(context, userGroupRoles.get(0).getRole());
roleText = MessageFormat.format(msgRole, roleMsg);
}
else
{
roleText = MessageFormat.format(msgRole, "[role]");
}
buf.append(roleText);
this.automaticText = buf.toString();
}
return outcome;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#determineOutcomeForStep(int)
*/
protected String determineOutcomeForStep(int step)
{
String outcome = null;
switch(step)
{
case 1:
{
outcome = "invite";
break;
}
case 2:
{
outcome = "notify";
break;
}
default:
{
outcome = CANCEL_OUTCOME;
}
}
return outcome;
}
/**
* @return a cached list of available folder permissions
*/
private Set<String> getFolderPermissions()
{
if (this.folderPermissions == null)
{
this.folderPermissions = this.permissionService.getSettablePermissions(ContentModel.TYPE_FOLDER);
}
return this.folderPermissions;
}
/**
* Simple wrapper class to represent a user/group and a role combination
*/
public static class UserGroupRole
{
public UserGroupRole(String authority, String role, String label)
{
this.authority = authority;
this.role = role;
this.label = label;
}
public String getAuthority()
{
return this.authority;
}
public String getRole()
{
return this.role;
}
public String getLabel()
{
return this.label;
}
private String authority;
private String role;
private String label;
}
}

View File

@@ -0,0 +1,236 @@
/*
* 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.web.bean.wizard;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.transaction.UserTransaction;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Handler class used by the New Action Wizard
*
* @author Kevin Roast
*/
public class NewActionWizard extends BaseActionWizard
{
private static Log logger = LogFactory.getLog(NewActionWizard.class);
private static final String ERROR = "error_action";
// TODO: retrieve these from the config service
private static final String WIZARD_TITLE_ID = "create_action_title";
private static final String WIZARD_DESC_ID = "create_action_desc";
private static final String STEP1_TITLE_ID = "create_action_step1_title";
private static final String STEP2_TITLE_ID = "create_action_step2_title";
private static final String FINISH_INSTRUCTION_ID = "create_action_finish_instruction";
/**
* Deals with the finish button being pressed
*
* @return outcome
*/
public String finish()
{
String outcome = FINISH_OUTCOME;
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
// build the action params map based on the selected action instance
Map<String, Serializable> actionParams = buildActionParams();
// build the action to execute
Action action = this.actionService.createAction(getAction());
action.setParameterValues(actionParams);
// execute the action on the current document node
this.actionService.executeAction(action, this.browseBean.getDocument().getNodeRef());
if (logger.isDebugEnabled())
{
logger.debug("Executed action '" + this.action +
"' with action params of " +
this.currentActionProperties);
}
// reset the current document properties/aspects in case we have changed them
// during the execution of the custom action
this.browseBean.getDocument().reset();
// commit the transaction
tx.commit();
}
catch (Exception e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), ERROR), e.getMessage()), e);
outcome = null;
}
return outcome;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardDescription()
*/
public String getWizardDescription()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_DESC_ID);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardTitle()
*/
public String getWizardTitle()
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_TITLE_ID);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepDescription()
*/
public String getStepDescription()
{
return "";
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepTitle()
*/
public String getStepTitle()
{
String stepTitle = null;
switch (this.currentStep)
{
case 1:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP1_TITLE_ID);
break;
}
case 2:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP2_TITLE_ID);
break;
}
case 3:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), SUMMARY_TITLE_ID);
break;
}
default:
{
stepTitle = "";
}
}
return stepTitle;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepInstructions()
*/
public String getStepInstructions()
{
String stepInstruction = null;
switch (this.currentStep)
{
case 3:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), FINISH_INSTRUCTION_ID);
break;
}
default:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), DEFAULT_INSTRUCTION_ID);
}
}
return stepInstruction;
}
/**
* Initialises the wizard
*/
public void init()
{
super.init();
}
/**
* @return Returns the summary data for the wizard.
*/
public String getSummary()
{
String summaryAction = this.actionService.getActionDefinition(
this.action).getTitle();
return buildSummary(
new String[] {"Action"},
new String[] {summaryAction});
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#determineOutcomeForStep(int)
*/
protected String determineOutcomeForStep(int step)
{
String outcome = null;
switch(step)
{
case 1:
{
outcome = "action";
break;
}
case 2:
{
outcome = this.action;
break;
}
case 3:
{
outcome = "summary";
break;
}
default:
{
outcome = CANCEL_OUTCOME;
}
}
return outcome;
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the GNU Lesser General Public License as
* published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.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.web.bean.wizard;
import java.util.ArrayList;
import java.util.List;
import javax.faces.context.FacesContext;
import org.alfresco.model.ForumModel;
import org.alfresco.web.ui.common.component.UIListItem;
/**
* Wizard bean used for creating and editing forum spaces
*
* @author gavinc
*/
public class NewForumWizard extends NewSpaceWizard
{
public static final String FORUM_ICON_DEFAULT = "forum_large";
protected String forumStatus;
protected List<UIListItem> forumIcons;
/**
* Returns the status of the forum
*
* @return The status of the forum
*/
public String getForumStatus()
{
return this.forumStatus;
}
/**
* Sets the status of the forum
*
* @param forumStatus The status
*/
public void setForumStatus(String forumStatus)
{
this.forumStatus = forumStatus;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#init()
*/
public void init()
{
super.init();
this.spaceType = ForumModel.TYPE_FORUM.toString();
this.icon = FORUM_ICON_DEFAULT;
this.forumStatus = "0";
}
/**
* Returns a list of icons to allow the user to select from.
*
* @return A list of icons
*/
@SuppressWarnings("unchecked")
public List<UIListItem> getIcons()
{
// return the various forum icons
if (this.forumIcons == null)
{
this.forumIcons = new ArrayList<UIListItem>(1);
UIListItem item = new UIListItem();
item.setValue(FORUM_ICON_DEFAULT);
item.getAttributes().put("image", "/images/icons/forum_large.gif");
this.forumIcons.add(item);
}
return this.forumIcons;
}
/**
* @see org.alfresco.web.bean.wizard.NewSpaceWizard#performCustomProcessing(javax.faces.context.FacesContext)
*/
@Override
protected void performCustomProcessing(FacesContext context)
{
// add or update the ForumModel.PROP_STATUS property depending on the editMode
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the GNU Lesser General Public License as
* published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.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.web.bean.wizard;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.model.ForumModel;
import org.alfresco.web.ui.common.component.UIListItem;
/**
* Wizard bean used for creating and editing forums spaces
*
* @author gavinc
*/
public class NewForumsWizard extends NewSpaceWizard
{
public static final String FORUMS_ICON_DEFAULT = "forums_large";
protected List<UIListItem> forumsIcons;
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#init()
*/
public void init()
{
super.init();
this.spaceType = ForumModel.TYPE_FORUMS.toString();
this.icon = FORUMS_ICON_DEFAULT;
}
/**
* Returns a list of icons to allow the user to select from.
*
* @return A list of icons
*/
@SuppressWarnings("unchecked")
public List<UIListItem> getIcons()
{
// return the various forums icons
if (this.forumsIcons == null)
{
this.forumsIcons = new ArrayList<UIListItem>(1);
UIListItem item = new UIListItem();
item.setValue(FORUMS_ICON_DEFAULT);
item.getAttributes().put("image", "/images/icons/forums_large.gif");
this.forumsIcons.add(item);
}
return this.forumsIcons;
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the GNU Lesser General Public License as
* published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.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.web.bean.wizard;
import javax.faces.context.FacesContext;
import org.alfresco.model.ForumModel;
import org.alfresco.util.GUID;
import org.alfresco.web.bean.repository.Repository;
/**
* Backing bean for posting forum articles.
*
* @author gavinc
*/
public class NewPostWizard extends CreateContentWizard
{
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#init()
*/
@Override
public void init()
{
super.init();
// set up for creating a post instead of HTML
this.createType = CONTENT_TEXT;
this.objectType = ForumModel.TYPE_POST.toString();
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#finish()
*/
@Override
public String finish()
{
// create appropriate values for filename, title and content type
this.fileName = GUID.generate() + ".txt";
this.contentType = Repository.getMimeTypeForFileName(
FacesContext.getCurrentInstance(), this.fileName);
this.title = this.fileName;
return super.finish();
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the GNU Lesser General Public License as
* published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.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.web.bean.wizard;
import javax.faces.event.ActionEvent;
import org.alfresco.model.ContentModel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Backing bean for posting replies to forum articles.
*
* @author gavinc
*/
public class NewReplyWizard extends NewPostWizard
{
private static Log logger = LogFactory.getLog(NewReplyWizard.class);
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#startWizard(javax.faces.event.ActionEvent)
*/
@Override
public void startWizard(ActionEvent event)
{
super.startWizard(event);
// also setup the content in the browse bean
this.browseBean.setupContentAction(event);
}
/**
* @see org.alfresco.web.bean.wizard.BaseContentWizard#performCustomProcessing()
*/
@Override
protected void performCustomProcessing()
{
if (this.editMode == false)
{
// setup the referencing aspect with the references association
// between the new post and the one being replied to
this.nodeService.addAspect(this.createdNode, ContentModel.ASPECT_REFERENCING, null);
this.nodeService.createAssociation(this.createdNode, this.browseBean.getDocument().getNodeRef(),
ContentModel.ASSOC_REFERENCES);
if (logger.isDebugEnabled())
{
logger.debug("created new node: " + this.createdNode);
logger.debug("existing node: " + this.browseBean.getDocument().getNodeRef());
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,223 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the GNU Lesser General Public License as
* published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.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.web.bean.wizard;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import org.alfresco.model.ContentModel;
import org.alfresco.model.ForumModel;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.component.UIListItem;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Wizard bean used for creating and editing topic spaces
*
* @author gavinc
*/
public class NewTopicWizard extends NewSpaceWizard
{
public static final String TOPIC_ICON_DEFAULT = "topic_large";
private static final Log logger = LogFactory.getLog(NewTopicWizard.class);
protected String message;
protected String topicType;
protected List<UIListItem> topicIcons;
protected List<SelectItem> topicTypes;
protected ContentService contentService;
/**
* Returns a list of topic types for the user to select from
*
* @return The topic types
*/
public List<SelectItem> getTopicTypes()
{
if (this.topicTypes == null)
{
this.topicTypes = new ArrayList<SelectItem>(3);
// TODO: change this to be based on categories
this.topicTypes.add(new SelectItem("1", "Announcement"));
this.topicTypes.add(new SelectItem("0", "Normal"));
this.topicTypes.add(new SelectItem("2", "Sticky"));
}
return this.topicTypes;
}
/**
* Returns the type of the topic
*
* @return The type of topic
*/
public String getTopicType()
{
return this.topicType;
}
/**
* Sets the type of the topic
*
* @param topicType The type of the topic
*/
public void setTopicType(String topicType)
{
this.topicType = topicType;
}
/**
* Returns the message entered by the user for the first post
*
* @return The message for the first post
*/
public String getMessage()
{
return this.message;
}
/**
* Sets the message
*
* @param message The message
*/
public void setMessage(String message)
{
this.message = message;
}
/**
* @param contentService The contentService to set.
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#init()
*/
public void init()
{
super.init();
this.spaceType = ForumModel.TYPE_TOPIC.toString();
this.icon = TOPIC_ICON_DEFAULT;
this.topicType = "0";
this.message = null;
}
/**
* Returns a list of icons to allow the user to select from.
*
* @return A list of icons
*/
@SuppressWarnings("unchecked")
public List<UIListItem> getIcons()
{
// return the various forum icons
if (this.topicIcons == null)
{
this.topicIcons = new ArrayList<UIListItem>(2);
UIListItem item = new UIListItem();
item.setValue(TOPIC_ICON_DEFAULT);
item.getAttributes().put("image", "/images/icons/topic_large.gif");
this.topicIcons.add(item);
}
return this.topicIcons;
}
/**
* @see org.alfresco.web.bean.wizard.NewSpaceWizard#performCustomProcessing(javax.faces.context.FacesContext)
*/
@Override
protected void performCustomProcessing(FacesContext context)
{
if (this.editMode == false)
{
// *************************
// TODO: Add or update the ForumModel.PROP_TYPE property depending on the editMode
// *************************
// get the node ref of the node that will contain the content
NodeRef containerNodeRef = this.createdNode;
// create a unique file name for the message content
String fileName = GUID.generate() + ".txt";
// create properties for content type
Map<QName, Serializable> contentProps = new HashMap<QName, Serializable>(5, 1.0f);
contentProps.put(ContentModel.PROP_NAME, fileName);
// create the node to represent the content
String assocName = QName.createValidLocalName(fileName);
ChildAssociationRef assocRef = this.nodeService.createNode(
containerNodeRef,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, assocName),
Repository.resolveToQName(ForumModel.TYPE_POST.toString()),
contentProps);
NodeRef postNodeRef = assocRef.getChildRef();
if (logger.isDebugEnabled())
logger.debug("Created post node with filename: " + fileName);
// apply the titled aspect - title and description
Map<QName, Serializable> titledProps = new HashMap<QName, Serializable>(3, 1.0f);
titledProps.put(ContentModel.PROP_TITLE, fileName);
this.nodeService.addAspect(postNodeRef, ContentModel.ASPECT_TITLED, titledProps);
if (logger.isDebugEnabled())
logger.debug("Added titled aspect with properties: " + titledProps);
Map<QName, Serializable> editProps = new HashMap<QName, Serializable>(1, 1.0f);
editProps.put(ContentModel.PROP_EDITINLINE, true);
this.nodeService.addAspect(postNodeRef, ContentModel.ASPECT_INLINEEDITABLE, editProps);
if (logger.isDebugEnabled())
logger.debug("Added inlineeditable aspect with properties: " + editProps);
// get a writer for the content and put the file
ContentWriter writer = contentService.getWriter(postNodeRef, ContentModel.PROP_CONTENT, true);
// set the mimetype and encoding
writer.setMimetype(Repository.getMimeTypeForFileName(context, fileName));
writer.setEncoding("UTF-8");
writer.putContent(this.message);
}
}
}

View File

@@ -0,0 +1,981 @@
/*
* 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.web.bean.wizard;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.validator.ValidatorException;
import javax.transaction.UserTransaction;
import org.alfresco.config.ConfigService;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.ContextListener;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.users.UsersBean;
import org.alfresco.web.config.ClientConfigElement;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.apache.log4j.Logger;
/**
* @author Kevin Roast
*/
public class NewUserWizard extends AbstractWizardBean
{
private static Logger logger = Logger.getLogger(NewUserWizard.class);
private static final String WIZARD_TITLE_NEW_ID = "new_user_title";
private static final String WIZARD_DESC_NEW_ID = "new_user_desc";
private static final String WIZARD_TITLE_EDIT_ID = "new_user_title_edit";
private static final String WIZARD_DESC_EDIT_ID = "new_user_desc_edit";
private static final String STEP1_TITLE_ID = "new_user_step1_title";
private static final String STEP1_DESCRIPTION_ID = "new_user_step1_desc";
private static final String STEP2_TITLE_ID = "new_user_step2_title";
private static final String STEP2_DESCRIPTION_ID = "new_user_step2_desc";
private static final String FINISH_INSTRUCTION_ID = "new_user_finish_instruction";
private static final String ERROR = "error_person";
/** form variables */
private String firstName = null;
private String lastName = null;
private String userName = null;
private String password = null;
private String confirm = null;
private String email = null;
private String companyId = null;
private String homeSpaceName = "";
private NodeRef homeSpaceLocation = null;
/** AuthenticationService bean reference */
private AuthenticationService authenticationService;
/** NamespaceService bean reference */
private NamespaceService namespaceService;
/** PermissionService bean reference */
private PermissionService permissionService;
/** PersonService bean reference */
private PersonService personService;
/** OwnableService bean reference */
private OwnableService ownableService;
/** ConfigService bean reference */
private ConfigService configService;
/** action context */
private Node person = null;
/** ref to system people folder */
private NodeRef peopleRef = null;
/** ref to the company home space folder */
private NodeRef companyHomeSpaceRef = null;
/**
* @param authenticationService The AuthenticationService to set.
*/
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
/**
* @param namespaceService The namespaceService to set.
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param permissionService The PermissionService to set.
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* @param personService The person service.
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
/**
* @param ownableService The ownableService to set.
*/
public void setOwnableService(OwnableService ownableService)
{
this.ownableService = ownableService;
}
/**
* @param configService The ConfigService to set.
*/
public void setConfigService(ConfigService configService)
{
this.configService = configService;
}
/**
* Initialises the wizard
*/
public void init()
{
super.init();
// reset all variables
this.firstName = "";
this.lastName = "";
this.userName = "";
this.password = "";
this.confirm = "";
this.email = "";
this.companyId = "";
this.homeSpaceName = "";
this.homeSpaceLocation = getCompanyHomeSpace();
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#populate()
*/
public void populate()
{
// set values for edit mode
Map<String, Object> props = getPerson().getProperties();
this.firstName = (String) props.get("firstName");
this.lastName = (String) props.get("lastName");
this.userName = (String) props.get("userName");
this.password = "";
this.confirm = "";
this.email = (String) props.get("email");
this.companyId = (String) props.get("organizationId");
// calculate home space name and parent space Id from homeFolderId
this.homeSpaceLocation = null; // default to Company root space
this.homeSpaceName = ""; // default to none set below root
NodeRef homeFolderRef = (NodeRef) props.get("homeFolder");
if (this.nodeService.exists(homeFolderRef) == true)
{
ChildAssociationRef childAssocRef = this.nodeService.getPrimaryParent(homeFolderRef);
NodeRef parentRef = childAssocRef.getParentRef();
if (this.nodeService.getRootNode(Repository.getStoreRef()).equals(parentRef) == false)
{
this.homeSpaceLocation = parentRef;
this.homeSpaceName = Repository.getNameForNode(nodeService, homeFolderRef);
}
else
{
this.homeSpaceLocation = homeFolderRef;
}
}
if (logger.isDebugEnabled())
logger.debug("Edit user home space location: " + homeSpaceLocation + " home space name: " + homeSpaceName);
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardDescription()
*/
public String getWizardDescription()
{
if (this.editMode)
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_DESC_EDIT_ID);
}
else
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_DESC_NEW_ID);
}
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getWizardTitle()
*/
public String getWizardTitle()
{
if (this.editMode)
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_TITLE_EDIT_ID);
}
else
{
return Application.getMessage(FacesContext.getCurrentInstance(), WIZARD_TITLE_NEW_ID);
}
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepTitle()
*/
public String getStepTitle()
{
String stepTitle = null;
switch (this.currentStep)
{
case 1:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP1_TITLE_ID);
break;
}
case 2:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), STEP2_TITLE_ID);
break;
}
case 3:
{
stepTitle = Application.getMessage(FacesContext.getCurrentInstance(), SUMMARY_TITLE_ID);
break;
}
default:
{
stepTitle = "";
}
}
return stepTitle;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepDescription()
*/
public String getStepDescription()
{
String stepDesc = null;
switch (this.currentStep)
{
case 1:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), STEP1_DESCRIPTION_ID);
break;
}
case 2:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), STEP2_DESCRIPTION_ID);
break;
}
case 3:
{
stepDesc = Application.getMessage(FacesContext.getCurrentInstance(), SUMMARY_DESCRIPTION_ID);
break;
}
default:
{
stepDesc = "";
}
}
return stepDesc;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#getStepInstructions()
*/
public String getStepInstructions()
{
String stepInstruction = null;
switch (this.currentStep)
{
case 3:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), FINISH_INSTRUCTION_ID);
break;
}
default:
{
stepInstruction = Application.getMessage(FacesContext.getCurrentInstance(), DEFAULT_INSTRUCTION_ID);
}
}
return stepInstruction;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#determineOutcomeForStep(int)
*/
protected String determineOutcomeForStep(int step)
{
String outcome = null;
switch (step)
{
case 1:
{
outcome = "person-properties";
break;
}
case 2:
{
outcome = "user-properties";
break;
}
case 3:
{
outcome = "summary";
break;
}
default:
{
outcome = CANCEL_OUTCOME;
}
}
return outcome;
}
/**
* @see org.alfresco.web.bean.wizard.AbstractWizardBean#finish()
*/
public String finish()
{
String outcome = FINISH_OUTCOME;
// TODO: implement create new Person object from specified details
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
if (this.editMode)
{
// update the existing node in the repository
NodeRef nodeRef = getPerson().getNodeRef();
Map<QName, Serializable> props = this.nodeService.getProperties(nodeRef);
props.put(ContentModel.PROP_USERNAME, this.userName);
props.put(ContentModel.PROP_FIRSTNAME, this.firstName);
props.put(ContentModel.PROP_LASTNAME, this.lastName);
// calculate whether we need to move the old home space or create new
NodeRef newHomeFolderRef;
NodeRef oldHomeFolderRef = (NodeRef)this.nodeService.getProperty(nodeRef, ContentModel.PROP_HOMEFOLDER);
boolean moveHomeSpace = false;
boolean renameHomeSpace = false;
if (oldHomeFolderRef != null && this.nodeService.exists(oldHomeFolderRef) == true)
{
// the original home folder ref exists so may need moving if it has been changed
ChildAssociationRef childAssocRef = this.nodeService.getPrimaryParent(oldHomeFolderRef);
NodeRef currentHomeSpaceLocation = childAssocRef.getParentRef();
if (this.homeSpaceName.length() != 0)
{
if (currentHomeSpaceLocation.equals(this.homeSpaceLocation) == false &&
oldHomeFolderRef.equals(this.homeSpaceLocation) == false &&
currentHomeSpaceLocation.equals(getCompanyHomeSpace()) == false)
{
moveHomeSpace = true;
}
String oldHomeSpaceName = Repository.getNameForNode(nodeService, oldHomeFolderRef);
if (oldHomeSpaceName.equals(this.homeSpaceName) == false &&
oldHomeFolderRef.equals(this.homeSpaceLocation) == false)
{
renameHomeSpace = true;
}
}
}
if (logger.isDebugEnabled())
logger.debug("Moving space: " + moveHomeSpace + " and renaming space: " + renameHomeSpace);
if (moveHomeSpace == false && renameHomeSpace == false)
{
if (this.homeSpaceLocation != null && this.homeSpaceName.length() != 0)
{
newHomeFolderRef = createHomeSpace(this.homeSpaceLocation.getId(), this.homeSpaceName, false);
}
else if (this.homeSpaceLocation != null)
{
// location selected but no home space name entered,
// so the home ref should be set to the newly selected space
newHomeFolderRef = this.homeSpaceLocation;
// set the permissions for this space so the user can access it
}
else
{
// nothing selected - use Company Home by default
newHomeFolderRef = getCompanyHomeSpace();
}
}
else
{
// either move, rename or both required
if (moveHomeSpace == true)
{
this.nodeService.moveNode(
oldHomeFolderRef,
this.homeSpaceLocation,
ContentModel.ASSOC_CONTAINS,
this.nodeService.getPrimaryParent(oldHomeFolderRef).getQName());
}
newHomeFolderRef = oldHomeFolderRef; // ref ID doesn't change
if (renameHomeSpace == true)
{
// change HomeSpace node name
this.nodeService.setProperty(newHomeFolderRef, ContentModel.PROP_NAME, this.homeSpaceName);
}
}
props.put(ContentModel.PROP_HOMEFOLDER, newHomeFolderRef);
props.put(ContentModel.PROP_EMAIL, this.email);
props.put(ContentModel.PROP_ORGID, this.companyId);
this.nodeService.setProperties(nodeRef, props);
// TODO: RESET HomeSpace Ref found in top-level navigation bar!
// NOTE: not need cos only admin can do this?
}
else
{
if (this.password.equals(this.confirm))
{
if (!this.personService.getUserNamesAreCaseSensitive())
{
this.userName = this.userName.toLowerCase();
}
// create properties for Person type from submitted Form data
Map<QName, Serializable> props = new HashMap<QName, Serializable>(7, 1.0f);
props.put(ContentModel.PROP_USERNAME, this.userName);
props.put(ContentModel.PROP_FIRSTNAME, this.firstName);
props.put(ContentModel.PROP_LASTNAME, this.lastName);
NodeRef homeSpaceNodeRef;
if (this.homeSpaceLocation != null && this.homeSpaceName.length() != 0)
{
// create new
homeSpaceNodeRef = createHomeSpace(this.homeSpaceLocation.getId(), this.homeSpaceName, true);
}
else if (this.homeSpaceLocation != null)
{
// set to existing
homeSpaceNodeRef = homeSpaceLocation;
setupHomeSpacePermissions(homeSpaceNodeRef);
}
else
{
// default to Company Home
homeSpaceNodeRef = getCompanyHomeSpace();
}
props.put(ContentModel.PROP_HOMEFOLDER, homeSpaceNodeRef);
props.put(ContentModel.PROP_EMAIL, this.email);
props.put(ContentModel.PROP_ORGID, this.companyId);
// create the node to represent the Person
String assocName = QName.createValidLocalName(this.userName);
NodeRef newPerson = this.personService.createPerson(props);
// ensure the user can access their own Person object
this.permissionService.setPermission(newPerson, this.userName, permissionService.getAllPermission(), true);
if (logger.isDebugEnabled()) logger.debug("Created Person node for username: " + this.userName);
// create the ACEGI Authentication instance for the new user
this.authenticationService.createAuthentication(this.userName, this.password.toCharArray());
if (logger.isDebugEnabled()) logger.debug("Created User Authentication instance for username: " + this.userName);
}
else
{
outcome = null;
Utils.addErrorMessage(Application.getMessage(context, UsersBean.ERROR_PASSWORD_MATCH));
}
}
// commit the transaction
tx.commit();
// reset the richlist component so it rebinds to the users list
invalidateUserList();
}
catch (Exception e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(FacesContext.getCurrentInstance(), ERROR), e
.getMessage()), e);
outcome = null;
}
return outcome;
}
/**
* @return Returns the summary data for the wizard.
*/
public String getSummary()
{
String homeSpaceLabel = this.homeSpaceName;
if (this.homeSpaceName.length() == 0 && this.homeSpaceLocation != null)
{
homeSpaceLabel = Repository.getNameForNode(this.nodeService, this.homeSpaceLocation);
}
ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance());
return buildSummary(new String[] { bundle.getString("name"), bundle.getString("username"),
bundle.getString("password"), bundle.getString("homespace") }, new String[] {
this.firstName + " " + this.lastName, this.userName, "********", homeSpaceLabel });
}
/**
* Init the users screen
*/
public void setupUsers(ActionEvent event)
{
invalidateUserList();
}
/**
* Action listener called when the wizard is being launched for editing an
* existing node.
*/
public void startWizardForEdit(ActionEvent event)
{
UIActionLink link = (UIActionLink) event.getComponent();
Map<String, String> params = link.getParameterMap();
String id = params.get("id");
if (id != null && id.length() != 0)
{
try
{
// create the node ref, then our node representation
NodeRef ref = new NodeRef(Repository.getStoreRef(), id);
Node node = new Node(ref);
// remember the Person node
setPerson(node);
// set the wizard in edit mode
this.editMode = true;
// populate the wizard's default values with the current value
// from the node being edited
init();
populate();
// clear the UI state in preparation for finishing the action
// and returning to the main page
invalidateUserList();
if (logger.isDebugEnabled()) logger.debug("Started wizard : " + getWizardTitle() + " for editing");
}
catch (InvalidNodeRefException refErr)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(FacesContext.getCurrentInstance(),
Repository.ERROR_NODEREF), new Object[] { id }));
}
}
else
{
setPerson(null);
}
}
/**
* @return Returns the companyId.
*/
public String getCompanyId()
{
return this.companyId;
}
/**
* @param companyId
* The companyId to set.
*/
public void setCompanyId(String companyId)
{
this.companyId = companyId;
}
/**
* @return Returns the email.
*/
public String getEmail()
{
return this.email;
}
/**
* @param email
* The email to set.
*/
public void setEmail(String email)
{
this.email = email;
}
/**
* @return Returns the firstName.
*/
public String getFirstName()
{
return this.firstName;
}
/**
* @param firstName The firstName to set.
*/
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
/**
* @return Returns the homeSpaceLocation.
*/
public NodeRef getHomeSpaceLocation()
{
return this.homeSpaceLocation;
}
/**
* @param homeSpaceLocation The homeSpaceLocation to set.
*/
public void setHomeSpaceLocation(NodeRef homeSpaceLocation)
{
this.homeSpaceLocation = homeSpaceLocation;
}
/**
* @return Returns the homeSpaceName.
*/
public String getHomeSpaceName()
{
return this.homeSpaceName;
}
/**
* @param homeSpaceName The homeSpaceName to set.
*/
public void setHomeSpaceName(String homeSpaceName)
{
this.homeSpaceName = homeSpaceName;
}
/**
* @return Returns the lastName.
*/
public String getLastName()
{
return this.lastName;
}
/**
* @param lastName The lastName to set.
*/
public void setLastName(String lastName)
{
this.lastName = lastName;
}
/**
* @return Returns the userName.
*/
public String getUserName()
{
return this.userName;
}
/**
* @param userName The userName to set.
*/
public void setUserName(String userName)
{
this.userName = userName;
}
/**
* @return Returns the password.
*/
public String getPassword()
{
return this.password;
}
/**
* @param password The password to set.
*/
public void setPassword(String password)
{
this.password = password;
}
/**
* @return Returns the confirm password.
*/
public String getConfirm()
{
return this.confirm;
}
/**
* @param confirm The confirm password to set.
*/
public void setConfirm(String confirm)
{
this.confirm = confirm;
}
/**
* @return Returns the person context.
*/
public Node getPerson()
{
return this.person;
}
/**
* @param person The person context to set.
*/
public void setPerson(Node person)
{
this.person = person;
}
public boolean getEditMode()
{
return this.editMode;
}
// ------------------------------------------------------------------------------
// Validator methods
/**
* Validate password field data is acceptable
*/
public void validatePassword(FacesContext context, UIComponent component, Object value) throws ValidatorException
{
String pass = (String) value;
if (pass.length() < 5 || pass.length() > 12)
{
String err = "Password must be between 5 and 12 characters in length.";
throw new ValidatorException(new FacesMessage(err));
}
for (int i = 0; i < pass.length(); i++)
{
if (Character.isLetterOrDigit(pass.charAt(i)) == false)
{
String err = "Password can only contain characters or digits.";
throw new ValidatorException(new FacesMessage(err));
}
}
}
/**
* Validate Username field data is acceptable
*/
public void validateUsername(FacesContext context, UIComponent component, Object value) throws ValidatorException
{
String pass = (String) value;
if (pass.length() < 5 || pass.length() > 12)
{
String err = "Username must be between 5 and 12 characters in length.";
throw new ValidatorException(new FacesMessage(err));
}
for (int i = 0; i < pass.length(); i++)
{
if (Character.isLetterOrDigit(pass.charAt(i)) == false)
{
String err = "Username can only contain characters or digits.";
throw new ValidatorException(new FacesMessage(err));
}
}
}
// ------------------------------------------------------------------------------
// Helper methods
/**
* Helper to return the company home space
*
* @return company home space NodeRef
*/
private NodeRef getCompanyHomeSpace()
{
if (this.companyHomeSpaceRef == null)
{
String companyXPath = Application.getRootPath(FacesContext.getCurrentInstance());
NodeRef rootNodeRef = this.nodeService.getRootNode(Repository.getStoreRef());
List<NodeRef> nodes = this.searchService.selectNodes(rootNodeRef, companyXPath, null, this.namespaceService,
false);
if (nodes.size() == 0)
{
throw new IllegalStateException("Unable to find company home space path: " + companyXPath);
}
this.companyHomeSpaceRef = nodes.get(0);
}
return this.companyHomeSpaceRef;
}
/**
* Create the specified home space if it does not exist, and return the ID
*
* @param locationId
* Parent location
* @param spaceName
* Home space to create, can be null to simply return the parent
* @param error
* True to throw an error if the space already exists, else
* ignore and return
*
* @return ID of the home space
*/
private NodeRef createHomeSpace(String locationId, String spaceName, boolean error)
{
String homeSpaceId = locationId;
NodeRef homeSpaceNodeRef = null;
if (spaceName != null && spaceName.length() != 0)
{
NodeRef parentRef = new NodeRef(Repository.getStoreRef(), locationId);
// check for existance of home space with same name - return immediately
// if it exists or throw an exception an give user chance to enter another name
// TODO: this might be better replaced with an XPath query!
List<ChildAssociationRef> children = this.nodeService.getChildAssocs(parentRef);
for (ChildAssociationRef ref : children)
{
String childNodeName = (String) this.nodeService.getProperty(ref.getChildRef(), ContentModel.PROP_NAME);
if (spaceName.equals(childNodeName))
{
if (error)
{
throw new AlfrescoRuntimeException("A Home Space with the same name already exists.");
}
else
{
return ref.getChildRef();
}
}
}
// space does not exist already, create a new Space under it with
// the specified name
String qname = QName.createValidLocalName(spaceName);
ChildAssociationRef assocRef = this.nodeService.createNode(parentRef, ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, qname), ContentModel.TYPE_FOLDER);
NodeRef nodeRef = assocRef.getChildRef();
// set the name property on the node
this.nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, spaceName);
if (logger.isDebugEnabled()) logger.debug("Created Home Space for with name: " + spaceName);
// apply the uifacets aspect - icon, title and description props
Map<QName, Serializable> uiFacetsProps = new HashMap<QName, Serializable>(3);
uiFacetsProps.put(ContentModel.PROP_ICON, NewSpaceWizard.SPACE_ICON_DEFAULT);
uiFacetsProps.put(ContentModel.PROP_TITLE, spaceName);
this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_UIFACETS, uiFacetsProps);
setupHomeSpacePermissions(nodeRef);
// return the ID of the created space
homeSpaceNodeRef = nodeRef;
homeSpaceId = nodeRef.getId();
}
return homeSpaceNodeRef;
}
/**
* Setup the default permissions for this and other users on the Home Space
*
* @param homeSpaceRef Home Space reference
*/
private void setupHomeSpacePermissions(NodeRef homeSpaceRef)
{
// Admin Authority has full permissions by default (automatic - set in the permission config)
// give full permissions to the new user
this.permissionService.setPermission(homeSpaceRef, this.userName, permissionService.getAllPermission(), true);
// by default other users will only have GUEST access to the space contents
// or whatever is configured as the default in the web-client-xml config
String permission = getDefaultPermission();
if (permission != null && permission.length() != 0)
{
this.permissionService.setPermission(homeSpaceRef, permissionService.getAllAuthorities(), permission, true);
}
// the new user is the OWNER of their own space and always has full permissions
this.ownableService.setOwner(homeSpaceRef, this.userName);
this.permissionService.setPermission(homeSpaceRef, permissionService.getOwnerAuthority(), permissionService.getAllPermission(), true);
// now detach (if we did this first we could not set any permissions!)
this.permissionService.setInheritParentPermissions(homeSpaceRef, false);
}
/**
* @return default permission string to set for other users for a new Home Space
*/
private String getDefaultPermission()
{
ClientConfigElement config = (ClientConfigElement)this.configService.getGlobalConfig().getConfigElement(
ClientConfigElement.CONFIG_ELEMENT_ID);
return config.getHomeSpacePermission();
}
private void invalidateUserList()
{
UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.web.config;
import java.util.Set;
import org.alfresco.config.evaluator.Evaluator;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
/**
* Evaluator that determines whether a given object has a particular aspect applied
*
* @author gavinc
*/
public class AspectEvaluator implements Evaluator
{
/**
* Determines whether the given aspect is applied to the given object
*
* @see org.alfresco.config.evaluator.Evaluator#applies(java.lang.Object, java.lang.String)
*/
public boolean applies(Object obj, String condition)
{
boolean result = false;
if (obj instanceof Node)
{
Set aspects = ((Node)obj).getAspects();
if (aspects != null)
{
QName spaceQName = Repository.resolveToQName(condition);
result = aspects.contains(spaceQName);
}
}
return result;
}
}

View File

@@ -0,0 +1,403 @@
/*
* 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.web.config;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.config.ConfigElement;
import org.alfresco.config.element.ConfigElementAdapter;
/**
* Custom config element that represents config values for the client
*
* @author Kevin Roast
*/
public class ClientConfigElement extends ConfigElementAdapter
{
public static final String CONFIG_ELEMENT_ID = "client";
public static final String VIEW_DETAILS = "details";
public static final String VIEW_ICONS = "icons";
public static final String VIEW_LIST = "list";
public static final String VIEW_BUBBLE = "bubble";
private static final String SEPARATOR = ":";
// defaults for any config values not supplied
private int defaultPageSize = 10;
private String defaultView = "details";
private String defaultSortColumn = "name";
private String defaultSortOrder = "ascending";
// list to store all the configured views
private List<String> views = new ArrayList<String>(4);
// map to store all the default views
private Map<String, String> defaultViews = new HashMap<String, String>(4);
// map to store all default pages sizes for configured client views
private Map<String, Integer> pagesSizes = new HashMap<String, Integer>(10);
// map to store default sort columns for configured views
private Map<String, String> sortColumns = new HashMap<String, String>(4);
// list of pages that have been configured to have ascending sorts
private List<String> descendingSorts = new ArrayList<String>(1);
private int recentSpacesItems = 6;
private int searchMinimum = 3;
private String helpUrl = null;
private String editLinkType = null;
private Map<String, String> localeMap = new HashMap<String, String>();
private List<String> languages = new ArrayList<String>(8);
private String homeSpacePermission = null;
private List<String> contentTypes = null;
private List<CustomProperty> customProps = null;
/**
* Default Constructor
*/
public ClientConfigElement()
{
super(CONFIG_ELEMENT_ID);
// add the default page sizes to the map
this.pagesSizes.put(VIEW_DETAILS, defaultPageSize);
this.pagesSizes.put(VIEW_LIST, defaultPageSize);
this.pagesSizes.put(VIEW_ICONS, 9);
this.pagesSizes.put(VIEW_BUBBLE, 5);
}
/**
* Constructor
*
* @param name Name of the element this config element represents
*/
public ClientConfigElement(String name)
{
super(name);
}
/**
* @see org.alfresco.config.element.ConfigElementAdapter#combine(org.alfresco.config.ConfigElement)
*/
public ConfigElement combine(ConfigElement configElement)
{
return null;
}
/**
* Adds a configured view
*
* @param renderer The implementation class of the view (the renderer)
*/
public void addView(String renderer)
{
this.views.add(renderer);
}
/**
* Returns a map of configured views for the client
*
* @return List of the implementation classes for the configured views
*/
public List<String> getViews()
{
return this.views;
}
/**
* Adds a default view setting
*
* @param page The page to set the default view for
* @param view The view name that will be the default
*/
public void addDefaultView(String page, String view)
{
this.defaultViews.put(page, view);
}
/**
* Returns the default view for the given page
*
* @param page The page to get the default view for
* @return The defualt view, if there isn't a configured default for the
* given page 'details' will be returned
*/
public String getDefaultView(String page)
{
String view = this.defaultViews.get(page);
if (view == null)
{
view = this.defaultView;
}
return view;
}
/**
* Adds a configured page size to the internal store
*
* @param page The name of the page i.e. browse, forums etc.
* @param view The name of the view the size is for i.e. details, icons etc.
* @param size The size of the page
*/
public void addDefaultPageSize(String page, String view, int size)
{
this.pagesSizes.put(page + SEPARATOR + view, new Integer(size));
}
/**
* Returns the page size for the given page and view combination
*
* @param page The name of the page i.e. browse, forums etc.
* @param view The name of the view the size is for i.e. details, icons etc.
* @return The size of the requested page, if the combination doesn't exist
* the default for the view will be used, if the view doesn't exist either
* 10 will be returned.
*/
public int getDefaultPageSize(String page, String view)
{
Integer pageSize = this.pagesSizes.get(page + SEPARATOR + view);
// try just the view if the combination isn't present
if (pageSize == null)
{
pageSize = this.pagesSizes.get(view);
// if the view is not present either default to 10
if (pageSize == null)
{
pageSize = new Integer(10);
}
}
return pageSize.intValue();
}
/**
* Adds a default sorting column for the given page
*
* @param page The name of the page i.e. browse, forums etc.
* @param column The name of the column to initially sort by
*/
public void addDefaultSortColumn(String page, String column)
{
this.sortColumns.put(page, column);
}
/**
* Returns the default sort column for the given page
*
* @param page The name of the page i.e. browse, forums etc.
* @return The name of the column to sort by, name is returned if
* the page is not found
*/
public String getDefaultSortColumn(String page)
{
String column = this.sortColumns.get(page);
if (column == null)
{
column = this.defaultSortColumn;
}
return column;
}
/**
* Sets the given page as using descending sorts
*
* @param page The name of the page i.e. browse, forums etc.
*/
public void addDescendingSort(String page)
{
this.descendingSorts.add(page);
}
/**
* Determines whether the given page has been
* configured to use descending sorting by default
*
* @param page The name of the page i.e. browse, forums etc.
* @return true if the page should use descending sorts
*/
public boolean hasDescendingSort(String page)
{
return this.descendingSorts.contains(page);
}
/**
* @return Returns the recentSpacesItems.
*/
public int getRecentSpacesItems()
{
return this.recentSpacesItems;
}
/**
* @param recentSpacesItems The recentSpacesItems to set.
*/
/*package*/ void setRecentSpacesItems(int recentSpacesItems)
{
this.recentSpacesItems = recentSpacesItems;
}
/**
* Add a language locale and display label to the list.
*
* @param locale Locale code
* @param label Display label
*/
/*package*/ void addLanguage(String locale, String label)
{
this.localeMap.put(locale, label);
this.languages.add(locale);
}
/**
* @return List of supported language locale strings in config file order
*/
public List<String> getLanguages()
{
return this.languages;
}
/**
* @param locale The locale string to lookup language label for
*
* @return the language label for specified locale string, or null if not found
*/
public String getLabelForLanguage(String locale)
{
return this.localeMap.get(locale);
}
/**
* @return Returns the help Url.
*/
public String getHelpUrl()
{
return this.helpUrl;
}
/**
* @param helpUrl The help Url to set.
*/
/*package*/ void setHelpUrl(String helpUrl)
{
this.helpUrl = helpUrl;
}
/**
* @return Returns the edit link type.
*/
public String getEditLinkType()
{
return this.editLinkType;
}
/**
* @param editLinkType The edit link type to set.
*/
/*package*/ void setEditLinkType(String editLinkType)
{
this.editLinkType = editLinkType;
}
/**
* @return Returns the search minimum number of characters.
*/
public int getSearchMinimum()
{
return this.searchMinimum;
}
/**
* @param searchMinimum The searchMinimum to set.
*/
/*package*/ void setSearchMinimum(int searchMinimum)
{
this.searchMinimum = searchMinimum;
}
/**
* @return Returns the default Home Space permissions.
*/
public String getHomeSpacePermission()
{
return this.homeSpacePermission;
}
/**
* @param homeSpacePermission The default Home Space permission to set.
*/
/*package*/ void setHomeSpacePermission(String homeSpacePermission)
{
this.homeSpacePermission = homeSpacePermission;
}
/**
* @return Returns the contentTypes.
*/
public List<String> getContentTypes()
{
return this.contentTypes;
}
/**
* @param contentTypes The contentTypes to set.
*/
/*package*/ void setContentTypes(List<String> contentTypes)
{
this.contentTypes = contentTypes;
}
/**
* @return Returns the customProps.
*/
public List<CustomProperty> getCustomProperties()
{
return this.customProps;
}
/**
* @param customProps The customProps to set.
*/
/*package*/ void setCustomProperties(List<CustomProperty> customProps)
{
this.customProps = customProps;
}
public static class CustomProperty
{
CustomProperty(String type, String aspect, String property)
{
Type = type;
Aspect = aspect;
Property = property;
}
public String Type;
public String Aspect;
public String Property;
}
}

Some files were not shown because too many files have changed in this diff Show More