Merge from HEAD to WCM-DEV2.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3659 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Britt Park
2006-09-02 18:19:00 +00:00
parent 3b1d6b89f5
commit cc6af1a45c
100 changed files with 4941 additions and 1298 deletions

View File

@@ -40,13 +40,12 @@ 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.AlfrescoNavigationHandler;
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.templating.OutputUtil;
import org.alfresco.web.templating.TemplatingService;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.apache.commons.logging.Log;
@@ -376,8 +375,8 @@ public class CheckinCheckoutBean
*/
private Node setupContentDocument(String id)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("Setup for action, setting current document to: " + id);
if (logger.isDebugEnabled())
logger.debug("Setup for action, setting current document to: " + id);
Node node = null;
@@ -427,14 +426,14 @@ public class CheckinCheckoutBean
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Trying to checkout content node Id: " + node.getId());
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())
if (logger.isDebugEnabled())
{
LOGGER.debug("Checkout copy location: " + getCopyLocation());
LOGGER.debug("Selected Space Id: " + this.selectedSpaceId);
logger.debug("Checkout copy location: " + getCopyLocation());
logger.debug("Selected Space Id: " + this.selectedSpaceId);
}
NodeRef workingCopyRef;
if (getCopyLocation().equals(COPYLOCATION_OTHER) && this.selectedSpaceId != null)
@@ -478,7 +477,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: checkoutFile called without a current Document!");
logger.warn("WARNING: checkoutFile called without a current Document!");
}
return outcome;
@@ -494,16 +493,22 @@ public class CheckinCheckoutBean
Node node = getWorkingDocument();
if (node != null)
{
// reset the underlying node
if (this.browseBean.getDocument() != null)
{
this.browseBean.getDocument().reset();
}
// clean up and clear action context
clearUpload();
setDocument(null);
setWorkingDocument(null);
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
else
{
LOGGER.warn("WARNING: checkoutFileOK called without a current WorkingDocument!");
logger.warn("WARNING: checkoutFileOK called without a current WorkingDocument!");
}
return outcome;
@@ -524,11 +529,11 @@ public class CheckinCheckoutBean
setDocument(null);
setWorkingDocument(null);
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
else
{
LOGGER.warn("WARNING: editFileOK called without a current Document!");
logger.warn("WARNING: editFileOK called without a current Document!");
}
return outcome;
@@ -567,17 +572,12 @@ public class CheckinCheckoutBean
MimetypeMap.MIMETYPE_JAVASCRIPT.equals(mimetype))
{
// make content available to the editing screen
String contentString = reader.getContentString();
setDocumentContent(contentString);
setEditorOutput(contentString);
// navigate to appropriate screen
FacesContext fc = FacesContext.getCurrentInstance();
this.navigator.setupDispatchContext(node);
String s = (MimetypeMap.MIMETYPE_XML.equals(mimetype)
? "editXmlInline"
: "editTextInline");
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, s);
setEditorOutput(reader.getContentString());
// navigate to appropriate screen
FacesContext fc = FacesContext.getCurrentInstance();
this.navigator.setupDispatchContext(node);
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "dialog:editTextInline");
}
else
{
@@ -588,7 +588,7 @@ public class CheckinCheckoutBean
// navigate to appropriate screen
FacesContext fc = FacesContext.getCurrentInstance();
this.navigator.setupDispatchContext(node);
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "editHtmlInline");
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "dialog:editHtmlInline");
}
}
}
@@ -598,7 +598,7 @@ public class CheckinCheckoutBean
// normal downloadable document
FacesContext fc = FacesContext.getCurrentInstance();
this.navigator.setupDispatchContext(node);
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "editFile");
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "dialog:editFile");
}
}
}
@@ -620,31 +620,23 @@ public class CheckinCheckoutBean
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Trying to update content node Id: " + node.getId());
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();
if (nodeService.getProperty(node.getNodeRef(),
TemplatingService.TT_QNAME) != null)
{
OutputUtil.regenerate(node.getNodeRef(),
this.contentService,
this.nodeService);
}
// clean up and clear action context
clearUpload();
setDocument(null);
setDocumentContent(null);
setEditorOutput(null);
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
catch (Throwable err)
{
@@ -656,7 +648,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: editInlineOK called without a current Document!");
logger.warn("WARNING: editInlineOK called without a current Document!");
}
return outcome;
@@ -679,7 +671,7 @@ public class CheckinCheckoutBean
clearUpload();
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
catch (Throwable err)
{
@@ -689,7 +681,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: undoCheckout called without a current WorkingDocument!");
logger.warn("WARNING: undoCheckout called without a current WorkingDocument!");
}
return outcome;
@@ -726,10 +718,10 @@ public class CheckinCheckoutBean
{
throw new IllegalStateException("Node supplied for undo checkout has neither Working Copy or Locked aspect!");
}
clearUpload();
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME + AlfrescoNavigationHandler.OUTCOME_SEPARATOR + "browse";
}
catch (Throwable err)
{
@@ -738,7 +730,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: undoCheckout called without a current WorkingDocument!");
logger.warn("WARNING: undoCheckout called without a current WorkingDocument!");
}
return outcome;
@@ -763,8 +755,8 @@ public class CheckinCheckoutBean
tx = Repository.getUserTransaction(context);
tx.begin();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Trying to checkin content node Id: " + node.getId());
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
@@ -816,7 +808,8 @@ public class CheckinCheckoutBean
setDocument(null);
clearUpload();
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME +
AlfrescoNavigationHandler.OUTCOME_SEPARATOR + "browse";
}
catch (Throwable err)
{
@@ -828,7 +821,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: checkinFileOK called without a current Document!");
logger.warn("WARNING: checkinFileOK called without a current Document!");
}
return outcome;
@@ -853,8 +846,8 @@ public class CheckinCheckoutBean
tx = Repository.getUserTransaction(context);
tx.begin();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Trying to update content node Id: " + node.getId());
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);
@@ -872,7 +865,7 @@ public class CheckinCheckoutBean
setDocument(null);
clearUpload();
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
catch (Throwable err)
{
@@ -884,7 +877,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: updateFileOK called without a current Document!");
logger.warn("WARNING: updateFileOK called without a current Document!");
}
return outcome;
@@ -898,7 +891,7 @@ public class CheckinCheckoutBean
// reset the state
clearUpload();
return "browse";
return AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
/**
@@ -929,7 +922,7 @@ public class CheckinCheckoutBean
// ------------------------------------------------------------------------------
// Private data
private static final Log LOGGER = LogFactory.getLog(CheckinCheckoutBean.class);
private static Log logger = LogFactory.getLog(CheckinCheckoutBean.class);
/** I18N messages */
private static final String MSG_ERROR_CHECKIN = "error_checkin";

View File

@@ -91,13 +91,21 @@ public class LoginBean
}
/**
* @param navigator The NavigationBean to set.
* @param navigator The NavigationBean to set.
*/
public void setNavigator(NavigationBean navigator)
{
this.navigator = navigator;
}
/**
* @param preferences The UserPreferencesBean to set
*/
public void setUserPreferencesBean(UserPreferencesBean preferences)
{
this.preferences = preferences;
}
/**
* @return true if the default Alfresco authentication process is being used, else false
* if an external authorisation mechanism is present.
@@ -329,7 +337,7 @@ public class LoginBean
else
{
// special case to handle jump to My Alfresco page initially
String location = Application.getClientConfig(FacesContext.getCurrentInstance()).getInitialLocation();
String location = this.preferences.getStartLocation();
if (NavigationBean.LOCATION_MYALFRESCO.equals(location))
{
return "myalfresco";
@@ -451,4 +459,7 @@ public class LoginBean
/** The NavigationBean bean reference */
protected NavigationBean navigator;
/** The user preferences bean reference */
protected UserPreferencesBean preferences;
}

View File

@@ -126,6 +126,14 @@ public class NavigationBean
this.contentDiskDriver = contentDiskDriver;
}
/**
* @param preferences The UserPreferencesBean to set
*/
public void setUserPreferencesBean(UserPreferencesBean preferences)
{
this.preferences = preferences;
}
/**
* @return the User object representing the current instance for this user
*/
@@ -252,6 +260,15 @@ public class NavigationBean
}
else if (LOCATION_MYALFRESCO.equals(location))
{
// make sure we set a current node ID as some screens expect this
if (getCurrentNodeId() == null)
{
String homeSpaceId = Application.getCurrentUser(context).getHomeSpaceId();
NodeRef homeSpaceRef = new NodeRef(Repository.getStoreRef(), homeSpaceId);
setCurrentNodeId(homeSpaceRef.getId());
}
// create a breadcrumb handler for this special case location (not a node)
List<IBreadcrumbHandler> elements = new ArrayList<IBreadcrumbHandler>(1);
elements.add(new IBreadcrumbHandler()
{
@@ -507,13 +524,8 @@ public class NavigationBean
{
if (this.location == null)
{
// get the initial location from the client config
String initialLocation = clientConfig.getInitialLocation();
if (initialLocation == null || initialLocation.length() == 0)
{
initialLocation = LOCATION_HOME;
}
processToolbarLocation(initialLocation, false);
// get the initial location from the user preferences
processToolbarLocation(this.preferences.getStartLocation(), false);
}
return this.location;
@@ -798,10 +810,10 @@ public class NavigationBean
private static Logger s_logger = Logger.getLogger(NavigationBean.class);
/** constant values used by the toolbar location modelist control */
static final String LOCATION_COMPANY = "companyhome";
static final String LOCATION_HOME = "userhome";
static final String LOCATION_GUEST = "guesthome";
static final String LOCATION_MYALFRESCO = "myalfresco";
public static final String LOCATION_COMPANY = "companyhome";
public static final String LOCATION_HOME = "userhome";
public static final String LOCATION_GUEST = "guesthome";
public static final String LOCATION_MYALFRESCO = "myalfresco";
private static final String MSG_MYALFRESCO = "my_alfresco";
@@ -828,6 +840,9 @@ public class NavigationBean
/** Client configuration object */
protected ClientConfigElement clientConfig = null;
/** The user preferences bean reference */
protected UserPreferencesBean preferences;
/** Cached path to our CIFS server and top level node DIR */
private String cifsServerPath;

View File

@@ -0,0 +1,66 @@
/*
* 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.util.ResourceBundle;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.PreferencesService;
/**
* Simple bean backing the user preferences settings.
*
* @author Kevin Roast
*/
public class UserPreferencesBean
{
private static final String PREF_STARTLOCATION = "start-location";
private static final String MSG_MYALFRESCO = "my_alfresco";
private static final String MSG_MYHOME = "my_home";
private static final String MSG_COMPANYHOME = "company_home";
private static final String MSG_GUESTHOME = "guest_home";
public String getStartLocation()
{
String location = (String)PreferencesService.getPreferences().getValue(PREF_STARTLOCATION);
if (location == null)
{
// default to value from client config
location = Application.getClientConfig(FacesContext.getCurrentInstance()).getInitialLocation();
}
return location;
}
public void setStartLocation(String location)
{
PreferencesService.getPreferences().setValue(PREF_STARTLOCATION, location);
}
public SelectItem[] getStartLocations()
{
ResourceBundle msg = Application.getBundle(FacesContext.getCurrentInstance());
return new SelectItem[] {
new SelectItem(NavigationBean.LOCATION_MYALFRESCO, msg.getString(MSG_MYALFRESCO)),
new SelectItem(NavigationBean.LOCATION_HOME, msg.getString(MSG_MYHOME)),
new SelectItem(NavigationBean.LOCATION_COMPANY, msg.getString(MSG_COMPANYHOME)),
new SelectItem(NavigationBean.LOCATION_GUEST, msg.getString(MSG_GUESTHOME))};
}
}

View File

@@ -6,7 +6,7 @@ import java.util.Map;
import javax.faces.context.FacesContext;
import org.alfresco.repo.action.executer.ScriptActionExecutor;
import org.alfresco.repo.action.executer.ScriptActionExecuter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.FacesHelper;
@@ -25,7 +25,7 @@ public class ScriptHandler extends BaseActionHandler
public String getJSPPath()
{
return getJSPPath(ScriptActionExecutor.NAME);
return getJSPPath(ScriptActionExecuter.NAME);
}
public void prepareForSave(Map<String, Serializable> actionProps,
@@ -34,13 +34,13 @@ public class ScriptHandler extends BaseActionHandler
// add the selected script noderef to the action properties
String id = (String)actionProps.get(PROP_SCRIPT);
NodeRef scriptRef = new NodeRef(Repository.getStoreRef(), id);
repoProps.put(ScriptActionExecutor.PARAM_SCRIPTREF, scriptRef);
repoProps.put(ScriptActionExecuter.PARAM_SCRIPTREF, scriptRef);
}
public void prepareForEdit(Map<String, Serializable> actionProps,
Map<String, Serializable> repoProps)
{
NodeRef scriptRef = (NodeRef)repoProps.get(ScriptActionExecutor.PARAM_SCRIPTREF);
NodeRef scriptRef = (NodeRef)repoProps.get(ScriptActionExecuter.PARAM_SCRIPTREF);
actionProps.put(PROP_SCRIPT, scriptRef.getId());
}

View File

@@ -34,8 +34,6 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.CopyService;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
@@ -182,12 +180,8 @@ public class ClipboardBean
*/
private void performPasteItems(int index, int action)
{
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (index == -1)
{
// paste all
@@ -219,16 +213,11 @@ public class ClipboardBean
}
}
// commit the transaction
tx.commit();
// refresh UI on success
UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
}
catch (Throwable 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);
}
@@ -241,7 +230,7 @@ public class ClipboardBean
* @param action the clipboard action to perform (see UIClipboardShelfItem)
*/
private void performClipboardOperation(ClipboardItem item, int action)
throws FileExistsException, FileNotFoundException
throws Throwable
{
NodeRef destRef = new NodeRef(Repository.getStoreRef(), this.navigator.getCurrentNodeId());
@@ -267,8 +256,12 @@ public class ClipboardBean
boolean operationComplete = false;
while (operationComplete == false)
{
UserTransaction tx = null;
try
{
// attempt each copy/paste in its own transaction
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (item.Mode == ClipboardStatus.COPY)
{
if (action == UIClipboardShelfItem.ACTION_PASTE_LINK)
@@ -399,10 +392,25 @@ public class ClipboardBean
throw fileExistsErr;
}
}
if (operationComplete == false)
catch (Throwable e)
{
String copyOf = Application.getMessage(FacesContext.getCurrentInstance(), MSG_COPY_OF);
name = copyOf + ' ' + name;
// some other type of exception occured - rollback and exit
throw e;
}
finally
{
// rollback if the operation didn't complete
if (operationComplete == false)
{
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
String copyOf = Application.getMessage(FacesContext.getCurrentInstance(), MSG_COPY_OF);
name = copyOf + ' ' + name;
}
else
{
// commit the transaction
tx.commit();
}
}
}
}

View File

@@ -1,23 +1,6 @@
/*
* 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.content;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
@@ -35,17 +18,9 @@ import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
import org.alfresco.web.templating.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.ContentWriter;
import java.io.OutputStreamWriter;
import org.alfresco.web.app.servlet.FacesHelper;
/**
* Bean implementation for the "Create Content Wizard" dialog
*
@@ -53,14 +28,12 @@ import org.alfresco.web.app.servlet.FacesHelper;
*/
public class CreateContentWizard extends BaseContentWizard
{
protected String content = null;
protected String templateTypeName;
protected List<SelectItem> createMimeTypes;
private static final Log LOGGER =
LogFactory.getLog(CreateContentWizard.class);
protected String content = null;
protected List<SelectItem> createMimeTypes;
private static Log logger = LogFactory.getLog(CreateContentWizard.class);
// ------------------------------------------------------------------------------
// Wizard implementation
@@ -68,28 +41,10 @@ public class CreateContentWizard extends BaseContentWizard
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
LOGGER.debug("saving file content to " + this.fileName);
saveContent(null, this.content);
if (this.templateTypeName != null)
{
LOGGER.debug("generating template output for " + this.templateTypeName);
this.nodeService.setProperty(this.createdNode,
TemplatingService.TT_QNAME,
this.templateTypeName);
TemplatingService ts = TemplatingService.getInstance();
TemplateType tt = this.getTemplateType();
OutputUtil.generate(this.createdNode,
ts.parseXML(this.content),
tt,
this.fileName,
this.getContainerNodeRef(),
this.fileFolderService,
this.contentService,
this.nodeService);
}
// return the default outcome
return outcome;
saveContent(null, this.content);
// return the default outcome
return outcome;
}
@Override
@@ -99,7 +54,6 @@ public class CreateContentWizard extends BaseContentWizard
this.content = null;
this.inlineEdit = true;
this.templateTypeName = null;
this.mimeType = MimetypeMap.MIMETYPE_HTML;
}
@@ -162,20 +116,6 @@ public class CreateContentWizard extends BaseContentWizard
{
this.content = content;
}
public List<SelectItem> getCreateTemplateTypes()
{
Collection<TemplateType> ttl = TemplatingService.getInstance().getTemplateTypes();
List<SelectItem> sil = new ArrayList<SelectItem>(ttl.size());
for (TemplateType tt : ttl)
{
sil.add(new SelectItem(tt.getName(), tt.getName()));
}
QuickSort sorter = new QuickSort(sil, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
return sil;
}
/**
* @return Returns a list of mime types to allow the user to select from
@@ -213,37 +153,18 @@ public class CreateContentWizard extends BaseContentWizard
}
else
{
LOGGER.warn("Could not find 'create-mime-types' configuration element");
logger.warn("Could not find 'create-mime-types' configuration element");
}
}
else
{
LOGGER.warn("Could not find 'Content Wizards' configuration section");
logger.warn("Could not find 'Content Wizards' configuration section");
}
}
return this.createMimeTypes;
}
public String getTemplateTypeName()
{
return this.templateTypeName;
}
public TemplateType getTemplateType()
{
final TemplatingService ts = TemplatingService.getInstance();
return ts.getTemplateType(this.getTemplateTypeName());
}
/**
* @param templateType Sets the currently selected template type
*/
public void setTemplateTypeName(final String templateTypeName)
{
this.templateTypeName = templateTypeName;
}
/**
* @return Returns the summary data for the wizard.

View File

@@ -0,0 +1,75 @@
package org.alfresco.web.bean.content;
import java.util.Map;
import javax.faces.context.FacesContext;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.dialog.BaseDialogBean;
import org.alfresco.web.bean.repository.Node;
/**
* Bean implementation of the "View Content Properties" dialog.
*
* @author gavinc
*/
public class ViewContentPropertiesDialog extends BaseDialogBean
{
protected static final String TEMP_PROP_MIMETYPE = "mimetype";
protected Node viewingNode;
// ------------------------------------------------------------------------------
// Dialog implementation
@Override
public void init(Map<String, String> parameters)
{
super.init(parameters);
// setup the editable node
this.viewingNode = 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.viewingNode.getProperties().get(ContentModel.PROP_CONTENT);
if (content != null)
{
this.viewingNode.getProperties().put(TEMP_PROP_MIMETYPE, content.getMimetype());
}
// add the specially handled 'size' property
this.viewingNode.addPropertyResolver("size", this.browseBean.resolverSize);
}
@Override
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
// nothing to do as the finish button is not shown and the dialog is read only
return outcome;
}
@Override
public String getCancelButtonLabel()
{
return Application.getMessage(FacesContext.getCurrentInstance(), "close");
}
// ------------------------------------------------------------------------------
// Bean getters and setters
/**
* Returns the node being viewed
*
* @return The node being viewed
*/
public Node getViewingNode()
{
return this.viewingNode;
}
}

View File

@@ -125,6 +125,14 @@ public class DashboardWizard extends BaseWizardBean
// ------------------------------------------------------------------------------
// Dashboard Wizard bean getters
/**
* @return true to allow the Guest user to configure the dashboard, false otherwise
*/
public boolean getAllowGuestConfig()
{
return DashboardManager.getDashboardConfig().getAllowGuestConfig();
}
/**
* @return The currently selected layout ID - used by the Dynamic Description component
*/

View File

@@ -0,0 +1,70 @@
/*
* 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.dashboard;
import javax.faces.context.FacesContext;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.NavigationBean;
/**
* Backing bean for the Getting Started Dashlet page.
*
* @author Kevin Roast
*/
public class GettingStartedBean
{
private NavigationBean navigationBean;
/**
* @param navigationBean The navigationBean to set.
*/
public void setNavigationBean(NavigationBean navigationBean)
{
this.navigationBean = navigationBean;
}
public String browseHomeSpace()
{
this.navigationBean.setCurrentNodeId(getHomeSpaceId());
return "browse";
}
public String createSpace()
{
this.navigationBean.setCurrentNodeId(getHomeSpaceId());
return "dialog:createSpace";
}
public String createContent()
{
this.navigationBean.setCurrentNodeId(getHomeSpaceId());
return "wizard:createContent";
}
public String addContent()
{
this.navigationBean.setCurrentNodeId(getHomeSpaceId());
return "addContent";
}
private String getHomeSpaceId()
{
return Application.getCurrentUser(FacesContext.getCurrentInstance()).getHomeSpaceId();
}
}

View File

@@ -59,6 +59,11 @@ public abstract class BaseDialogBean implements IDialogBean
this.isFinished = false;
}
public void restored()
{
// do nothing by default, subclasses can override if necessary
}
public String cancel()
{
return getDefaultCancelOutcome();
@@ -126,6 +131,16 @@ public abstract class BaseDialogBean implements IDialogBean
return true;
}
public String getTitle()
{
return null;
}
public String getDescription()
{
return null;
}
/**
* @param browseBean The BrowseBean to set.
*/

View File

@@ -20,11 +20,10 @@ import org.alfresco.web.ui.common.component.UIActionLink;
*
* @author gavinc
*/
public class DialogManager
public final class DialogManager
{
protected IDialogBean currentDialog;
protected DialogConfig currentDialogConfig;
protected Map<String, String> currentDialogParams;
private DialogState currentDialogState;
private Map<String, String> paramsToApply;
/**
* Action handler used to setup parameters for the dialog being launched
@@ -38,7 +37,7 @@ public class DialogManager
if (component instanceof UIActionLink)
{
// store the parameters
this.currentDialogParams = ((UIActionLink)component).getParameterMap();
this.paramsToApply = ((UIActionLink)component).getParameterMap();
}
}
@@ -49,22 +48,48 @@ public class DialogManager
*/
public void setCurrentDialog(DialogConfig config)
{
this.currentDialogConfig = config;
String beanName = this.currentDialogConfig.getManagedBean();
this.currentDialog = (IDialogBean)FacesHelper.getManagedBean(
String beanName = config.getManagedBean();
IDialogBean dialog = (IDialogBean)FacesHelper.getManagedBean(
FacesContext.getCurrentInstance(), beanName);
if (this.currentDialog == null)
if (dialog == null)
{
throw new AlfrescoRuntimeException("Failed to find managed bean '" + beanName + "'");
}
// initialise the managed bean
this.currentDialog.init(this.currentDialogParams);
dialog.init(this.paramsToApply);
// reset the current parameters so subsequent dialogs don't get them
this.currentDialogParams = null;
this.paramsToApply = null;
// create the DialogState object
this.currentDialogState = new DialogState(config, dialog);
}
/**
* Returns the state of the currently active dialog
*
* @return Current dialog's state
*/
public DialogState getState()
{
return this.currentDialogState;
}
/**
* Restores the dialog represented by the given DialogState object.
* NOTE: The dialog's restored() method is also called during this
* method.
*
* @param state The DialogState for the dialog to restore
*/
public void restoreState(DialogState state)
{
this.currentDialogState = state;
// retrieve the dialog and call it's restored() method
this.currentDialogState.getDialog().restored();
}
/**
@@ -74,7 +99,7 @@ public class DialogManager
*/
public DialogConfig getCurrentDialog()
{
return this.currentDialogConfig;
return this.currentDialogState.getConfig();
}
/**
@@ -84,7 +109,7 @@ public class DialogManager
*/
public IDialogBean getBean()
{
return this.currentDialog;
return this.currentDialogState.getDialog();
}
/**
@@ -94,7 +119,7 @@ public class DialogManager
*/
public String getIcon()
{
return this.currentDialogConfig.getIcon();
return this.currentDialogState.getConfig().getIcon();
}
/**
@@ -105,7 +130,7 @@ public class DialogManager
public String getErrorMessage()
{
return Application.getMessage(FacesContext.getCurrentInstance(),
this.currentDialogConfig.getErrorMessageId());
this.currentDialogState.getConfig().getErrorMessageId());
}
/**
@@ -115,15 +140,23 @@ public class DialogManager
*/
public String getTitle()
{
String title = this.currentDialogConfig.getTitleId();
// try and get the title directly from the dialog
String title = this.currentDialogState.getDialog().getTitle();
if (title != null)
if (title == null)
{
title = Application.getMessage(FacesContext.getCurrentInstance(), title);
}
else
{
title = this.currentDialogConfig.getTitle();
// try and get the title via a message bundle key
title = this.currentDialogState.getConfig().getTitleId();
if (title != null)
{
title = Application.getMessage(FacesContext.getCurrentInstance(), title);
}
else
{
// try and get the title from the configuration
title = this.currentDialogState.getConfig().getTitle();
}
}
return title;
@@ -136,15 +169,23 @@ public class DialogManager
*/
public String getDescription()
{
String desc = this.currentDialogConfig.getDescriptionId();
// try and get the description directly from the dialog
String desc = this.currentDialogState.getDialog().getDescription();
if (desc != null)
if (desc == null)
{
desc = Application.getMessage(FacesContext.getCurrentInstance(), desc);
}
else
{
desc = this.currentDialogConfig.getDescription();
// try and get the description via a message bundle key
desc = this.currentDialogState.getConfig().getDescriptionId();
if (desc != null)
{
desc = Application.getMessage(FacesContext.getCurrentInstance(), desc);
}
else
{
// try and get the description from the configuration
desc = this.currentDialogState.getConfig().getDescription();
}
}
return desc;
@@ -158,7 +199,7 @@ public class DialogManager
*/
public String getActions()
{
return this.currentDialogConfig.getActionsConfigId();
return this.currentDialogState.getConfig().getActionsConfigId();
}
/**
@@ -168,7 +209,7 @@ public class DialogManager
*/
public String getPage()
{
return this.currentDialogConfig.getPage();
return this.currentDialogState.getConfig().getPage();
}
/**
@@ -178,7 +219,7 @@ public class DialogManager
*/
public boolean isOKButtonVisible()
{
return this.currentDialogConfig.isOKButtonVisible();
return this.currentDialogState.getConfig().isOKButtonVisible();
}
/**
@@ -191,10 +232,10 @@ public class DialogManager
List<DialogButtonConfig> buttons = null;
// get a list of buttons to display from the configuration
List<DialogButtonConfig> cfgButtons = this.currentDialogConfig.getButtons();
List<DialogButtonConfig> cfgButtons = this.currentDialogState.getConfig().getButtons();
// get a list of buttons added dynamically by the dialog
List<DialogButtonConfig> dynButtons = this.currentDialog.getAdditionalButtons();
List<DialogButtonConfig> dynButtons = this.currentDialogState.getDialog().getAdditionalButtons();
if (cfgButtons != null && dynButtons != null)
{
@@ -223,7 +264,7 @@ public class DialogManager
*/
public String getCancelButtonLabel()
{
return this.currentDialog.getCancelButtonLabel();
return this.currentDialogState.getDialog().getCancelButtonLabel();
}
/**
@@ -233,7 +274,7 @@ public class DialogManager
*/
public String getFinishButtonLabel()
{
return this.currentDialog.getFinishButtonLabel();
return this.currentDialogState.getDialog().getFinishButtonLabel();
}
/**
@@ -243,7 +284,7 @@ public class DialogManager
*/
public boolean getFinishButtonDisabled()
{
return this.currentDialog.getFinishButtonDisabled();
return this.currentDialogState.getDialog().getFinishButtonDisabled();
}
/**
@@ -253,7 +294,7 @@ public class DialogManager
*/
public String finish()
{
return this.currentDialog.finish();
return this.currentDialogState.getDialog().finish();
}
/**
@@ -263,6 +304,6 @@ public class DialogManager
*/
public String cancel()
{
return this.currentDialog.cancel();
return this.currentDialogState.getDialog().cancel();
}
}

View File

@@ -0,0 +1,53 @@
package org.alfresco.web.bean.dialog;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.config.DialogsConfigElement.DialogConfig;
/**
* Object responsible for holding the current state of an active dialog.
*
* @author gavinc
*/
public final class DialogState
{
private DialogConfig config;
private IDialogBean dialog;
/**
* Default constructor
*
* @param config The configuration for the dialog
* @param dialog The dialog bean instance
*/
public DialogState(DialogConfig config, IDialogBean dialog)
{
this.config = config;
this.dialog = dialog;
}
/**
* Returns the configuration for the dialog
*
* @return The dialog configuration
*/
public DialogConfig getConfig()
{
return config;
}
/**
* Returns the bean representing the dialog instance
*
* @return The dialog bean instance
*/
public IDialogBean getDialog()
{
return dialog;
}
@Override
public String toString()
{
return AlfrescoNavigationHandler.DIALOG_PREFIX + this.config.getName();
}
}

View File

@@ -19,6 +19,11 @@ public interface IDialogBean
*/
public void init(Map<String, String> parameters);
/**
* Called when the dialog is restored after a nested dialog is closed
*/
public void restored();
/**
* Method handler called when the cancel button of the dialog is pressed
*
@@ -60,4 +65,22 @@ public interface IDialogBean
* @return true if the button should be disabled
*/
public boolean getFinishButtonDisabled();
/**
* Returns the title to be used for the dialog
* <p>If this returns null the DialogManager will
* lookup the title via the dialog configuration</p>
*
* @return The title or null if the title is to be acquired via configuration
*/
public String getTitle();
/**
* Returns the description to be used for the dialog
* <p>If this returns null the DialogManager will
* lookup the description via the dialog configuration</p>
*
* @return The title or null if the title is to be acquired via configuration
*/
public String getDescription();
}

View File

@@ -12,7 +12,6 @@ import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
*/
public class HeaderSeparatorGenerator extends SeparatorGenerator
{
@Override
protected String getHtml(UIComponent component, PropertySheetItem item)
{
String html = "<div class='wizardSectionHeading mainSubTitle' style='margin-top: 6px; margin-bottom: 6px;'>&nbsp;" +

View File

@@ -0,0 +1,79 @@
package org.alfresco.web.bean.generator;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
/**
* Generates a component to represent a separator.
* <p>The HTML to be used for the separator is configured via the
* <code>setHtml</code> method.
*
* @author gavinc
*/
public class HtmlSeparatorGenerator extends BaseComponentGenerator
{
protected String html = "<b>default</b>";
/**
* Returns the HTML configured to be used for this separator
*
* @return The HTML to display
*/
public String getHtml()
{
return html;
}
/**
* Sets the HTML to display for the separator
*
* @param html The HTML
*/
public void setHtml(String html)
{
this.html = html;
}
@SuppressWarnings("unchecked")
public UIComponent generate(FacesContext context, String id)
{
UIComponent component = this.createOutputTextComponent(context, id);
component.getAttributes().put("escape", Boolean.FALSE);
return component;
}
@Override
@SuppressWarnings("unchecked")
protected UIComponent createComponent(FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem item)
{
UIComponent component = this.generate(context, item.getName());
// set the HTML to use
component.getAttributes().put("value", getResolvedHtml(component, item));
return component;
}
/**
* Returns the resolved HTML to use for the separator.
* <p>In the default case we just return the HTML set
* via setHtml however subclasses may choose to generate
* the resulting HTML using a combination of the HTML set
* via setHtml and the given PropertySheetItem.
*
* @param component The JSF component representing the separator
* @param item The separator item
* @return The resolved HTML
*/
protected String getResolvedHtml(UIComponent component, PropertySheetItem item)
{
// In the default case we just return the HTML set via setHtml
return this.html;
}
}

View File

@@ -0,0 +1,85 @@
package org.alfresco.web.bean.generator;
import javax.faces.component.UIComponent;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
/**
* Generates a component to represent a separator that uses the
* property sheet display label configuration. The CSS class used
* for the HTML representing the label can also be configured via
* the <code>setStyleClass</code> method.
*
* @author gavinc
*/
public class LabelSeparatorGenerator extends HtmlSeparatorGenerator
{
protected String style = "margin-top: 6px; margin-bottom: 6px;";
protected String styleClass;
/**
* Returns the CSS class configured to be used for this separator
*
* @return The CSS class
*/
public String getStyleClass()
{
return styleClass;
}
/**
* Sets the CSS class to use for the separator
*
* @param styleClass The CSS class
*/
public void setStyleClass(String styleClass)
{
this.styleClass = styleClass;
}
/**
* Returns the CSS style configured to be used for this separator
*
* @return The CSS style
*/
public String getStyle()
{
return style;
}
/**
* Sets the CSS style to use for the separator
*
* @param style The CSS style
*/
public void setStyle(String style)
{
this.style = style;
}
@Override
protected String getResolvedHtml(UIComponent component, PropertySheetItem item)
{
StringBuilder htmlBuilder = new StringBuilder("<div");
if (this.styleClass != null && this.styleClass.length() > 0)
{
htmlBuilder.append(" class=\"");
htmlBuilder.append(this.styleClass);
htmlBuilder.append("\"");
}
if (this.style != null && this.style.length() > 0)
{
htmlBuilder.append(" style=\"");
htmlBuilder.append(this.style);
htmlBuilder.append("\"");
}
// add the display label and close the div
htmlBuilder.append(">&nbsp;");
htmlBuilder.append(item.getDisplayLabel());
htmlBuilder.append("</div>");
return htmlBuilder.toString();
}
}

View File

@@ -1,49 +1,16 @@
package org.alfresco.web.bean.generator;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
/**
* Generates a component to represent a separator.
* Generates a component to represent a separator using the HTML <code>&lt;hr/&gt;</code> element.
*
* @author gavinc
*/
public class SeparatorGenerator extends BaseComponentGenerator
public class SeparatorGenerator extends HtmlSeparatorGenerator
{
@SuppressWarnings("unchecked")
public UIComponent generate(FacesContext context, String id)
public SeparatorGenerator()
{
UIComponent component = this.createOutputTextComponent(context, id);
component.getAttributes().put("escape", Boolean.FALSE);
// For the standard separator just show a <hr/> element
return component;
}
@Override
@SuppressWarnings("unchecked")
protected UIComponent createComponent(FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem item)
{
UIComponent component = this.generate(context, item.getName());
// set the HTML to use
component.getAttributes().put("value", getHtml(component, item));
return component;
}
/**
* Returns the HTML to display for the separator
*
* @param component The JSF component representing the separator
* @param item The separator item
* @return The HTML
*/
protected String getHtml(UIComponent component, PropertySheetItem item)
{
return "<div style='margin-top: 6px; margin-bottom: 6px;'><hr/></div>";
this.html = "<div style='margin-top: 6px; margin-bottom: 6px;'><hr/></div>";
}
}

View File

@@ -1,7 +1,9 @@
package org.alfresco.web.bean.repository;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
@@ -10,6 +12,8 @@ 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.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
@@ -54,9 +58,6 @@ public class TransientNode extends Node
// initialise the node
initNode(data);
if (logger.isDebugEnabled())
logger.debug("Constructed transient node: " + this);
}
/**
@@ -93,11 +94,64 @@ public class TransientNode extends Node
{
if (assocDef.isChild())
{
this.childAssociations.put(item, data.get(item));
// TODO: handle lists of NodeRef's
NodeRef child = null;
Object obj = data.get(item);
if (obj instanceof String)
{
child = new NodeRef((String)obj);
}
else if (obj instanceof NodeRef)
{
child = (NodeRef)obj;
}
else if (obj instanceof List)
{
if (logger.isWarnEnabled())
logger.warn("0..* child associations are not supported yet");
}
if (child != null)
{
// create a child association reference, add it to a list and add the list
// to the list of child associations for this node
List<ChildAssociationRef> assocs = new ArrayList<ChildAssociationRef>(1);
ChildAssociationRef childRef = new ChildAssociationRef(assocDef.getName(), this.nodeRef,
null, child);
assocs.add(childRef);
this.childAssociations.put(item, assocs);
}
}
else
{
this.associations.put(item, data.get(item));
// TODO: handle lists of NodeRef's
NodeRef target = null;
Object obj = data.get(item);
if (obj instanceof String)
{
target = new NodeRef((String)obj);
}
else if (obj instanceof NodeRef)
{
target = (NodeRef)obj;
}
else if (obj instanceof List)
{
if (logger.isWarnEnabled())
logger.warn("0..* associations are not supported yet");
}
if (target != null)
{
// create a association reference, add it to a list and add the list
// to the list of associations for this node
List<AssociationRef> assocs = new ArrayList<AssociationRef>(1);
AssociationRef assocRef = new AssociationRef(this.nodeRef, assocDef.getName(), target);
assocs.add(assocRef);
this.associations.put(item, assocs);
}
}
}
}
@@ -140,7 +194,7 @@ public class TransientNode extends Node
// don't reset anything otherwise we'll lose our data
// with no way of getting it back!!
}
@Override
public String toString()
{

View File

@@ -130,7 +130,7 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
Set<String> mailedAuthorities = new HashSet<String>(usersGroups.size());
// walk the list of users/groups to notify
// walk the list of users/groups to notify - handle duplicates along the way
for (Map node : usersGroups)
{
String authority = (String)node.get(PROP_USERNAME);
@@ -254,31 +254,47 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
tx = Repository.getUserTransaction(context, true);
tx.begin();
// Return all the permissions set against the current node
// for any authentication instance (user/group).
// Then combine them into a single list for each authentication found.
// Return all the permissions set against the current node for any authentication
// instance (user/group), walking the parent space inheritance chain.
// Then combine them into a single list for each authentication found.
String currentAuthority = Application.getCurrentUser(context).getUserName();
Map<String, List<String>> permissionMap = new HashMap<String, List<String>>(8, 1.0f);
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(getSpace().getNodeRef());
for (AccessPermission permission : permissions)
NodeRef spaceRef = getSpace().getNodeRef();
while (spaceRef != null)
{
// 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.GUEST ||
permission.getAuthorityType() == AuthorityType.EVERYONE))
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(spaceRef);
for (AccessPermission permission : permissions)
{
String authority = permission.getAuthority();
List<String> userPermissions = permissionMap.get(authority);
if (userPermissions == null)
// we are only interested in Allow and not Guest/Everyone/owner
if (permission.getAccessStatus() == AccessStatus.ALLOWED &&
(permission.getAuthorityType() == AuthorityType.USER ||
permission.getAuthorityType() == AuthorityType.GROUP))
{
// create for first time
userPermissions = new ArrayList<String>(4);
permissionMap.put(authority, userPermissions);
String authority = permission.getAuthority();
if (currentAuthority.equals(authority) == false)
{
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());
}
}
// add the permission name for this authority
userPermissions.add(permission.getPermission());
}
// walk parent inheritance chain until root or no longer inherits
if (permissionService.getInheritParentPermissions(spaceRef))
{
spaceRef = nodeService.getPrimaryParent(spaceRef).getParentRef();
}
else
{
spaceRef = null;
}
}
@@ -316,79 +332,6 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
}
return this.usersGroups;
}
/**
* Build a Map representing a user/group with a set of useful property values required
* by the UIUserGroupPicker UI component.
*
* @param authority User/Group authority
* @param roles Role text for the authority
*
* @return Map
*/
private Map buildAuthorityMap(String authority, String roles)
{
Map node = null;
if (AuthorityType.getAuthorityType(authority) == AuthorityType.GUEST ||
this.personService.personExists(authority))
{
NodeRef nodeRef = this.personService.getPerson(authority);
if (nodeRef != null)
{
// create our Node representation
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 = ((MapNode)node).getProperties();
props.put(PROP_FULLNAME, ((String)props.get("firstName")) + ' ' + ((String)props.get("lastName")));
props.put(PROP_ICON, WebResources.IMAGE_PERSON);
props.put(PROP_ISGROUP, false);
}
}
else if (AuthorityType.getAuthorityType(authority) == AuthorityType.GROUP)
{
// need a map (dummy node) to represent props for this Group Authority
node = new HashMap<String, Object>(8, 1.0f);
if (authority.startsWith(PermissionService.GROUP_PREFIX) == true)
{
node.put(PROP_FULLNAME, authority.substring(PermissionService.GROUP_PREFIX.length()));
}
else
{
node.put(PROP_FULLNAME, authority);
}
node.put(PROP_USERNAME, authority);
node.put(PROP_ID, authority);
node.put(PROP_ICON, WebResources.IMAGE_GROUP);
node.put(PROP_ISGROUP, true);
node.put(PROP_EXPANDED, false);
}
if (node != null)
{
// add the common properties
node.put(PROP_ROLES, roles);
node.put(PROP_PARENT, null);
if (this.userGroupLookup.get(authority) != null)
{
// this authority already exists in the list somewhere else - mark as duplicate
node.put(PROP_DUPLICATE, true);
node.put(PROP_SELECTED, false);
}
else
{
// add to table for the first time, not a duplicate
this.userGroupLookup.put(authority, node);
node.put(PROP_DUPLICATE, false);
node.put(PROP_SELECTED, true);
}
}
return node;
}
/**
* @return TemplateMailHelperBean instance for this wizard
@@ -398,6 +341,29 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
return this.mailHelper;
}
/**
* @return true if any authorities are selected, false otherwise
*/
public boolean getFinishButtonDisabled()
{
boolean disabled = true;
if (this.usersGroups != null)
{
for (Map userGroup : this.usersGroups)
{
if (((Boolean)userGroup.get(PROP_EXPANDED)) == false &&
((Boolean)userGroup.get(PROP_SELECTED)) == true)
{
disabled = false;
break;
}
}
}
return disabled;
}
// ------------------------------------------------------------------------------
// Action Event Listeners
@@ -435,16 +401,25 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
{
// expand the list for this group by adding the immediate child authorities
boolean selected = (Boolean)userGroup.get(PROP_SELECTED);
String currentAuthority =
Application.getCurrentUser(FacesContext.getCurrentInstance()).getUserName();
Set<String> authorities = authorityService.getContainedAuthorities(
null, pickerEvent.Authority, true);
for (String authority : authorities)
{
Map node = buildAuthorityMap(authority, (String)userGroup.get(PROP_ROLES));
if (node != null)
if (currentAuthority.equals(authority) == false)
{
node.put(PROP_PARENT, userGroup);
node.put(PROP_SELECTED, selected);
this.usersGroups.add(++index, node);
if (AuthorityType.getAuthorityType(authority) == AuthorityType.USER ||
AuthorityType.getAuthorityType(authority) == AuthorityType.GROUP)
{
Map node = buildAuthorityMap(authority, (String)userGroup.get(PROP_ROLES));
if (node != null)
{
node.put(PROP_PARENT, userGroup);
node.put(PROP_SELECTED, selected);
this.usersGroups.add(++index, node);
}
}
}
}
}
@@ -494,4 +469,81 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
}
}
}
// ------------------------------------------------------------------------------
// Private helpers
/**
* Build a Map representing a user/group with a set of useful property values required
* by the UIUserGroupPicker UI component.
*
* @param authority User/Group authority
* @param roles Role text for the authority
*
* @return Map
*/
private Map buildAuthorityMap(String authority, String roles)
{
Map node = null;
if (AuthorityType.getAuthorityType(authority) == AuthorityType.GUEST ||
this.personService.personExists(authority))
{
NodeRef nodeRef = this.personService.getPerson(authority);
if (nodeRef != null)
{
// create our Node representation
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 = ((MapNode)node).getProperties();
props.put(PROP_FULLNAME, ((String)props.get("firstName")) + ' ' + ((String)props.get("lastName")));
props.put(PROP_ICON, WebResources.IMAGE_PERSON);
props.put(PROP_ISGROUP, false);
}
}
else if (AuthorityType.getAuthorityType(authority) == AuthorityType.GROUP)
{
// need a map (dummy node) to represent props for this Group Authority
node = new HashMap<String, Object>(8, 1.0f);
if (authority.startsWith(PermissionService.GROUP_PREFIX) == true)
{
node.put(PROP_FULLNAME, authority.substring(PermissionService.GROUP_PREFIX.length()));
}
else
{
node.put(PROP_FULLNAME, authority);
}
node.put(PROP_USERNAME, authority);
node.put(PROP_ID, authority);
node.put(PROP_ICON, WebResources.IMAGE_GROUP);
node.put(PROP_ISGROUP, true);
}
if (node != null)
{
// add the common properties
node.put(PROP_ROLES, roles);
node.put(PROP_PARENT, null);
node.put(PROP_EXPANDED, false);
if (this.userGroupLookup.get(authority) != null)
{
// this authority already exists in the list somewhere else - mark as duplicate
node.put(PROP_DUPLICATE, true);
node.put(PROP_SELECTED, false);
}
else
{
// add to table for the first time, not a duplicate
this.userGroupLookup.put(authority, node);
node.put(PROP_DUPLICATE, false);
node.put(PROP_SELECTED, true);
}
}
return node;
}
}

View File

@@ -26,16 +26,12 @@ import org.apache.commons.logging.LogFactory;
*
* @author gavinc
*/
public class WizardManager
public final class WizardManager
{
private static Log logger = LogFactory.getLog(WizardManager.class);
protected int currentStep = 1;
protected PageConfig currentPageCfg;
protected WizardConfig currentWizardConfig;
protected IWizardBean currentWizard;
protected List<StepConfig> steps;
protected Map<String, String> currentWizardParams;
private WizardState currentWizardState;
private Map<String, String> paramsToApply;
/**
* Action handler used to setup parameters for the wizard being launched
@@ -49,7 +45,7 @@ public class WizardManager
if (component instanceof UIActionLink)
{
// store the parameters
this.currentWizardParams = ((UIActionLink)component).getParameterMap();
this.paramsToApply = ((UIActionLink)component).getParameterMap();
}
}
@@ -60,31 +56,53 @@ public class WizardManager
*/
public void setCurrentWizard(WizardConfig config)
{
this.currentStep = 1;
this.currentWizardConfig = config;
String beanName = this.currentWizardConfig.getManagedBean();
this.currentWizard = (IWizardBean)FacesHelper.getManagedBean(
String beanName = config.getManagedBean();
IWizardBean wizard = (IWizardBean)FacesHelper.getManagedBean(
FacesContext.getCurrentInstance(), beanName);
if (this.currentWizard == null)
if (wizard == null)
{
throw new AlfrescoRuntimeException("Failed to find managed bean '" + beanName + "'");
}
// initialise the managed bean
this.currentWizard.init(this.currentWizardParams);
wizard.init(this.paramsToApply);
// reset the current parameters so subsequent wizards don't get them
this.currentWizardParams = null;
this.paramsToApply = null;
// get the steps for the wizard
this.steps = this.currentWizardConfig.getStepsAsList();
// create the WizardState object
this.currentWizardState = new WizardState(config, wizard);
// setup the first step
determineCurrentPage();
}
/**
* Returns the state of the currently active wizard
*
* @return Current wizard's state
*/
public WizardState getState()
{
return this.currentWizardState;
}
/**
* Restores the wizard represented by the given WizardState object.
* NOTE: The wizard's restored() method is also called during this
* method.
*
* @param state The WizardState for the wizard to restore
*/
public void restoreState(WizardState state)
{
this.currentWizardState = state;
// retrieve the wizard and call it's restored() method
this.currentWizardState.getWizard().restored();
}
/**
* Returns the config for the current wizard
*
@@ -92,7 +110,7 @@ public class WizardManager
*/
public WizardConfig getCurrentWizard()
{
return this.currentWizardConfig;
return this.currentWizardState.getConfig();
}
/**
@@ -102,7 +120,7 @@ public class WizardManager
*/
public IWizardBean getBean()
{
return this.currentWizard;
return this.currentWizardState.getWizard();
}
/**
@@ -112,7 +130,7 @@ public class WizardManager
*/
public String getIcon()
{
return this.currentWizardConfig.getIcon();
return this.currentWizardState.getConfig().getIcon();
}
/**
@@ -123,7 +141,7 @@ public class WizardManager
public String getErrorMessage()
{
return Application.getMessage(FacesContext.getCurrentInstance(),
this.currentWizardConfig.getErrorMessageId());
this.currentWizardState.getConfig().getErrorMessageId());
}
/**
@@ -133,15 +151,23 @@ public class WizardManager
*/
public String getTitle()
{
String title = this.currentWizardConfig.getTitleId();
// try and get the title directly from the wizard
String title = this.currentWizardState.getWizard().getTitle();
if (title != null)
if (title == null)
{
title = Application.getMessage(FacesContext.getCurrentInstance(), title);
}
else
{
title = this.currentWizardConfig.getTitle();
// try and get the title via a message bundle key
title = this.currentWizardState.getConfig().getTitleId();
if (title != null)
{
title = Application.getMessage(FacesContext.getCurrentInstance(), title);
}
else
{
// try and get the title from the configuration
title = this.currentWizardState.getConfig().getTitle();
}
}
return title;
@@ -154,15 +180,23 @@ public class WizardManager
*/
public String getDescription()
{
String desc = this.currentWizardConfig.getDescriptionId();
// try and get the description directly from the dialog
String desc = this.currentWizardState.getWizard().getDescription();
if (desc != null)
if (desc == null)
{
desc = Application.getMessage(FacesContext.getCurrentInstance(), desc);
}
else
{
desc = this.currentWizardConfig.getDescription();
// try and get the description via a message bundle key
desc = this.currentWizardState.getConfig().getDescriptionId();
if (desc != null)
{
desc = Application.getMessage(FacesContext.getCurrentInstance(), desc);
}
else
{
// try and get the description from the configuration
desc = this.currentWizardState.getConfig().getDescription();
}
}
return desc;
@@ -175,7 +209,7 @@ public class WizardManager
*/
public int getCurrentStep()
{
return this.currentStep;
return this.currentWizardState.getCurrentStep();
}
/**
@@ -185,7 +219,7 @@ public class WizardManager
*/
public String getCurrentStepAsString()
{
return Integer.toString(this.currentStep);
return Integer.toString(this.currentWizardState.getCurrentStep());
}
/**
@@ -197,7 +231,8 @@ public class WizardManager
*/
public String getCurrentStepName()
{
return ((StepConfig)this.steps.get(this.currentStep-1)).getName();
return ((StepConfig)this.currentWizardState.getSteps().get(
this.currentWizardState.getCurrentStep()-1)).getName();
}
/**
@@ -207,12 +242,12 @@ public class WizardManager
*/
public List<UIListItem> getStepItems()
{
List<UIListItem> items = new ArrayList<UIListItem>(this.steps.size());
List<UIListItem> items = new ArrayList<UIListItem>(this.currentWizardState.getSteps().size());
for (int x = 0; x < this.steps.size(); x++)
for (int x = 0; x < this.currentWizardState.getSteps().size(); x++)
{
String uiStepNumber = Integer.toString(x + 1);
StepConfig stepCfg = this.steps.get(x);
StepConfig stepCfg = this.currentWizardState.getSteps().get(x);
UIListItem item = new UIListItem();
item.setValue(uiStepNumber);
@@ -255,7 +290,7 @@ public class WizardManager
*/
public String getPage()
{
return this.currentPageCfg.getPath();
return this.currentWizardState.getCurrentPageCfg().getPath();
}
/**
@@ -265,7 +300,7 @@ public class WizardManager
*/
public String getStepTitle()
{
String title = this.currentPageCfg.getTitleId();
String title = this.currentWizardState.getCurrentPageCfg().getTitleId();
if (title != null)
{
@@ -273,7 +308,7 @@ public class WizardManager
}
else
{
title = this.currentPageCfg.getTitle();
title = this.currentWizardState.getCurrentPageCfg().getTitle();
}
return title;
@@ -286,7 +321,7 @@ public class WizardManager
*/
public String getStepDescription()
{
String desc = this.currentPageCfg.getDescriptionId();
String desc = this.currentWizardState.getCurrentPageCfg().getDescriptionId();
if (desc != null)
{
@@ -294,7 +329,7 @@ public class WizardManager
}
else
{
desc = this.currentPageCfg.getDescription();
desc = this.currentWizardState.getCurrentPageCfg().getDescription();
}
return desc;
@@ -307,7 +342,7 @@ public class WizardManager
*/
public String getStepInstructions()
{
String instruction = this.currentPageCfg.getInstructionId();
String instruction = this.currentWizardState.getCurrentPageCfg().getInstructionId();
if (instruction != null)
{
@@ -315,7 +350,7 @@ public class WizardManager
}
else
{
instruction = this.currentPageCfg.getInstruction();
instruction = this.currentWizardState.getCurrentPageCfg().getInstruction();
}
return instruction;
@@ -328,7 +363,7 @@ public class WizardManager
*/
public String getNextButtonLabel()
{
return this.currentWizard.getNextButtonLabel();
return this.currentWizardState.getWizard().getNextButtonLabel();
}
/**
@@ -338,13 +373,13 @@ public class WizardManager
*/
public boolean getNextButtonDisabled()
{
if (this.currentStep == this.steps.size())
if (this.currentWizardState.getCurrentStep() == this.currentWizardState.getSteps().size())
{
return true;
}
else
{
return this.currentWizard.getNextButtonDisabled();
return this.currentWizardState.getWizard().getNextButtonDisabled();
}
}
@@ -355,7 +390,7 @@ public class WizardManager
*/
public String getBackButtonLabel()
{
return this.currentWizard.getBackButtonLabel();
return this.currentWizardState.getWizard().getBackButtonLabel();
}
/**
@@ -365,7 +400,7 @@ public class WizardManager
*/
public boolean getBackButtonDisabled()
{
if (this.currentStep == 1)
if (this.currentWizardState.getCurrentStep() == 1)
{
return true;
}
@@ -382,7 +417,7 @@ public class WizardManager
*/
public String getCancelButtonLabel()
{
return this.currentWizard.getCancelButtonLabel();
return this.currentWizardState.getWizard().getCancelButtonLabel();
}
/**
@@ -392,7 +427,7 @@ public class WizardManager
*/
public String getFinishButtonLabel()
{
return this.currentWizard.getFinishButtonLabel();
return this.currentWizardState.getWizard().getFinishButtonLabel();
}
/**
@@ -402,13 +437,13 @@ public class WizardManager
*/
public boolean getFinishButtonDisabled()
{
if (this.currentStep == this.steps.size())
if (this.currentWizardState.getCurrentStep() == this.currentWizardState.getSteps().size())
{
return false;
}
else
{
return this.currentWizard.getFinishButtonDisabled();
return this.currentWizardState.getWizard().getFinishButtonDisabled();
}
}
@@ -419,13 +454,16 @@ public class WizardManager
*/
public void next()
{
this.currentStep++;
// calculate next step number and update wizard state
int currentStep = this.currentWizardState.getCurrentStep();
currentStep++;
this.currentWizardState.setCurrentStep(currentStep);
if (logger.isDebugEnabled())
logger.debug("next called, current step is now: " + this.currentStep);
logger.debug("next called, current step is now: " + this.currentWizardState.getCurrentStep());
// tell the wizard the next button has been pressed
this.currentWizard.next();
this.currentWizardState.getWizard().next();
determineCurrentPage();
}
@@ -437,13 +475,16 @@ public class WizardManager
*/
public void back()
{
this.currentStep--;
// calculate next step number and update wizard state
int currentStep = this.currentWizardState.getCurrentStep();
currentStep--;
this.currentWizardState.setCurrentStep(currentStep);
if (logger.isDebugEnabled())
logger.debug("back called, current step is now: " + this.currentStep);
logger.debug("back called, current step is now: " + this.currentWizardState.getCurrentStep());
// tell the wizard the back button has been pressed
this.currentWizard.back();
this.currentWizardState.getWizard().back();
determineCurrentPage();
}
@@ -455,7 +496,7 @@ public class WizardManager
*/
public String finish()
{
return this.currentWizard.finish();
return this.currentWizardState.getWizard().finish();
}
/**
@@ -465,7 +506,7 @@ public class WizardManager
*/
public String cancel()
{
return this.currentWizard.cancel();
return this.currentWizardState.getWizard().cancel();
}
/**
@@ -473,10 +514,14 @@ public class WizardManager
*/
protected void determineCurrentPage()
{
this.currentPageCfg = null;
// reset the current page config in the state object
this.currentWizardState.setCurrentPageCfg(null);
PageConfig currentPageCfg = null;
// get the config for the current step position
StepConfig stepCfg = this.steps.get(this.currentStep-1);
StepConfig stepCfg = this.currentWizardState.getSteps().get(
this.currentWizardState.getCurrentStep()-1);
// is the step conditional?
if (stepCfg.hasConditionalPages())
@@ -497,25 +542,28 @@ public class WizardManager
Object obj = vb.getValue(context);
if (obj instanceof Boolean && ((Boolean)obj).booleanValue())
{
this.currentPageCfg = pageCfg;
currentPageCfg = pageCfg;
break;
}
}
}
// if none of the conditions passed use the default page
if (this.currentPageCfg == null)
if (currentPageCfg == null)
{
this.currentPageCfg = stepCfg.getDefaultPage();
currentPageCfg = stepCfg.getDefaultPage();
}
if (this.currentPageCfg == null)
if (currentPageCfg == null)
{
throw new AlfrescoRuntimeException("Failed to determine page for step '" + stepCfg.getName() +
"'. Make sure a default page is configured.");
}
// save the current page config in the state object
this.currentWizardState.setCurrentPageCfg(currentPageCfg);
if (logger.isDebugEnabled())
logger.debug("Config for current page: " + this.currentPageCfg);
logger.debug("Config for current page: " + this.currentWizardState.getCurrentPageCfg());
}
}

View File

@@ -0,0 +1,113 @@
package org.alfresco.web.bean.wizard;
import java.util.List;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.config.WizardsConfigElement.PageConfig;
import org.alfresco.web.config.WizardsConfigElement.StepConfig;
import org.alfresco.web.config.WizardsConfigElement.WizardConfig;
/**
* Object responsible for holding the current state of an active wizard.
*
* @author gavinc
*/
public final class WizardState
{
private int currentStep = 1;
private PageConfig currentPageCfg;
private WizardConfig config;
private IWizardBean wizard;
private List<StepConfig> steps;
/**
* Default constructor
*
* @param config The configuration for the wizard
* @param wizard The wizard bean instance
*/
public WizardState(WizardConfig config, IWizardBean wizard)
{
this.config = config;
this.wizard = wizard;
this.steps = this.config.getStepsAsList();
}
/**
* Sets the configuration for the current page of the wizard
*
* @param currentPageCfg The configuration
*/
public void setCurrentPageCfg(PageConfig currentPageCfg)
{
this.currentPageCfg = currentPageCfg;
}
/**
* Sets the current step the wizard is on
*
* @param currentStep The current step number
*/
public void setCurrentStep(int currentStep)
{
this.currentStep = currentStep;
}
/**
* Returns the wizard bean instance
*
* @return The wizard bean instance
*/
public IWizardBean getWizard()
{
return this.wizard;
}
/**
* Returns the configuration for the current wizard
*
* @return The wizard configuration
*/
public WizardConfig getConfig()
{
return this.config;
}
/**
* Returns the configuration for the current page of the wizard
*
* @return The current page configuration
*/
public PageConfig getCurrentPageCfg()
{
return currentPageCfg;
}
/**
* The current step the wizard is on
*
* @return The current wizard step
*/
public int getCurrentStep()
{
return currentStep;
}
/**
* Returns the list of steps the wizard has
*
* @return List of wizard steps
*/
public List<StepConfig> getSteps()
{
return steps;
}
@Override
public String toString()
{
return AlfrescoNavigationHandler.WIZARD_PREFIX + this.config.getName() +
"[" + this.currentStep + "]";
}
}

View File

@@ -0,0 +1,667 @@
package org.alfresco.web.bean.workflow;
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.faces.event.ActionEvent;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowInstance;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
import org.alfresco.service.cmr.workflow.WorkflowTransition;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.dialog.BaseDialogBean;
import org.alfresco.web.bean.repository.MapNode;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.NodePropertyResolver;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.TransientNode;
import org.alfresco.web.config.DialogsConfigElement.DialogButtonConfig;
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.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Bean implementation for the "Manage Task" dialog.
*
* @author gavinc
*/
public class ManageTaskDialog extends BaseDialogBean
{
protected WorkflowService workflowService;
protected Node taskNode;
protected WorkflowTask task;
protected WorkflowInstance workflowInstance;
protected WorkflowTransition[] transitions;
protected NodeRef workflowPackage;
protected List<Node> resources;
protected TaskCompleteResolver completeResolver = new TaskCompleteResolver();
protected UIRichList packageItemsRichList;
protected List<String> packageItemsToAdd;
protected List<String> packageItemsToRemove;
protected String[] itemsToAdd;
protected boolean isItemBeingAdded = false;
protected final Log logger = LogFactory.getLog(getClass());
protected static final String ID_PREFIX = "transition_";
protected static final String CLIENT_ID_PREFIX = AlfrescoNavigationHandler.DIALOG_PREFIX + ID_PREFIX;
// ------------------------------------------------------------------------------
// Dialog implementation
@Override
public void init(Map<String, String> parameters)
{
super.init(parameters);
// reset variables
this.task = null;
this.taskNode = null;
this.workflowInstance = null;
this.transitions = null;
this.workflowPackage = null;
this.resources = null;
this.itemsToAdd = null;
this.packageItemsToAdd = null;
this.packageItemsToRemove = null;
this.isItemBeingAdded = false;
if (this.packageItemsRichList != null)
{
this.packageItemsRichList.setValue(null);
this.packageItemsRichList = null;
}
// get the task details
String taskId = this.parameters.get("id");
this.task = this.workflowService.getTaskById(taskId);
if (this.task != null)
{
// setup a transient node to represent the task we're managing
WorkflowTaskDefinition taskDef = this.task.definition;
this.taskNode = new TransientNode(taskDef.metadata.getName(),
"task_" + System.currentTimeMillis(), this.task.properties);
// get access to the workflow instance for the task
this.workflowInstance = this.task.path.instance;
// setup the workflow package for the task
Serializable obj = this.task.properties.get(WorkflowModel.ASSOC_PACKAGE);
// TODO: remove this workaroud where JBPM may return a String and not the NodeRef
if (obj instanceof NodeRef)
{
this.workflowPackage = (NodeRef)obj;
}
else if (obj instanceof String)
{
this.workflowPackage = new NodeRef((String)obj);
}
if (logger.isDebugEnabled())
{
logger.debug("Task: " + this.task);
logger.debug("Trasient node: " + this.taskNode);
logger.debug("Workflow package: " + this.workflowPackage );
}
}
}
@Override
public void restored()
{
// reset the workflow package rich list so everything gets re-evaluated
if (this.packageItemsRichList != null)
{
this.packageItemsRichList.setValue(null);
this.packageItemsRichList = null;
}
}
@Override
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
if (logger.isDebugEnabled())
logger.debug("Saving task: " + this.task.id);
// prepare the edited parameters for saving
Map<QName, Serializable> params = WorkflowBean.prepareTaskParams(this.taskNode);
if (logger.isDebugEnabled())
logger.debug("Saving task with parameters: " + params);
// remove any items the user selected to remove
if (this.workflowPackage != null && this.packageItemsToRemove != null &&
this.packageItemsToRemove.size() > 0)
{
for (String removedItem : this.packageItemsToRemove)
{
this.nodeService.removeChild(this.workflowPackage, new NodeRef(removedItem));
}
}
// add any items the user selected to add
if (this.workflowPackage != null && this.packageItemsToAdd != null &&
this.packageItemsToAdd.size() > 0)
{
for (String addedItem : this.packageItemsToAdd)
{
NodeRef addedNodeRef = new NodeRef(addedItem);
this.nodeService.addChild(this.workflowPackage, addedNodeRef,
ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
QName.createValidLocalName((String)this.nodeService.getProperty(
addedNodeRef, ContentModel.PROP_NAME))));
}
}
// update the task with the updated parameters
this.workflowService.updateTask(this.task.id, params, null, null);
return outcome;
}
@Override
public List<DialogButtonConfig> getAdditionalButtons()
{
List<DialogButtonConfig> buttons = null;
if (this.task != null)
{
// get the transitions available from this task and
// show them in the dialog as additional buttons
this.transitions = this.task.path.node.transitions;
if (this.transitions != null)
{
buttons = new ArrayList<DialogButtonConfig>(this.transitions.length);
for (WorkflowTransition trans : this.transitions)
{
buttons.add(new DialogButtonConfig(ID_PREFIX + trans.title, trans.title, null,
"#{DialogManager.bean.transition}", "false", null));
}
}
}
return buttons;
}
@Override
public String getFinishButtonLabel()
{
return Application.getMessage(FacesContext.getCurrentInstance(), "save");
}
@Override
public boolean getFinishButtonDisabled()
{
return false;
}
@Override
public String getTitle()
{
String titleStart = Application.getMessage(FacesContext.getCurrentInstance(), "manage_task_title");
return titleStart + ": " + this.task.title;
}
@Override
public String getDescription()
{
return this.task.description;
}
// ------------------------------------------------------------------------------
// Event handlers
@SuppressWarnings("unused")
public String transition()
{
String outcome = getDefaultFinishOutcome();
if (logger.isDebugEnabled())
logger.debug("Transitioning task: " + this.task.id);
// to find out which transition button was pressed we need
// to look for the button's id in the request parameters,
// the first non-null result is the button that was pressed.
FacesContext context = FacesContext.getCurrentInstance();
Map reqParams = context.getExternalContext().getRequestParameterMap();
String selectedTransition = null;
for (WorkflowTransition trans : this.transitions)
{
Object result = reqParams.get(CLIENT_ID_PREFIX + trans.title);
if (result != null)
{
// this was the button that was pressed
selectedTransition = trans.id;
break;
}
}
if (selectedTransition != null)
{
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(context);
tx.begin();
// prepare the edited parameters for saving
Map<QName, Serializable> params = WorkflowBean.prepareTaskParams(this.taskNode);
if (logger.isDebugEnabled())
logger.debug("Transitioning task with parameters: " + params);
// update the task with the updated parameters
this.workflowService.updateTask(this.task.id, params, null, null);
// signal the selected transition to the workflow task
this.workflowService.endTask(this.task.id, selectedTransition);
// commit the changes
tx.commit();
if (logger.isDebugEnabled())
logger.debug("Ended task with transition: " + selectedTransition);
}
catch (Throwable e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(formatErrorMessage(e), e);
outcome = this.getErrorOutcome(e);
}
}
return outcome;
}
/**
* Prepares the dialog to allow the user to add an item to the workflow package
*
* @param event The event
*/
public void prepareForAdd(ActionEvent event)
{
this.isItemBeingAdded = true;
}
/**
* Cancels the adding of an item to the workflow package
*
* @param event The event
*/
public void cancelAddPackageItems(ActionEvent event)
{
this.isItemBeingAdded = false;
}
/**
* Adds an item to the workflow package
*
* @param event The event
*/
public void addPackageItems(ActionEvent event)
{
if (this.itemsToAdd != null)
{
if (this.packageItemsToAdd == null)
{
// create the list of items to add if necessary
this.packageItemsToAdd = new ArrayList<String>(this.itemsToAdd.length);
}
for (String item : this.itemsToAdd)
{
// if this item is in the remove list it means it was there originally
// and has now been re-added, as a result we don't need to do anything
// to the original workflow package, therefore remove from the remove list
if (this.packageItemsToRemove != null && this.packageItemsToRemove.contains(item))
{
this.packageItemsToRemove.remove(item);
if (logger.isDebugEnabled())
logger.debug("Removed item from the removed list: " + item);
}
else
{
this.packageItemsToAdd.add(item);
if (logger.isDebugEnabled())
logger.debug("Added item to the added list: " + item);
}
}
// reset the rich list so it re-renders
this.packageItemsRichList.setValue(null);
}
this.isItemBeingAdded = false;
this.itemsToAdd = null;
}
/**
* Removes an item from the workflow package
*
* @param event The event containing a reference to the item to remove
*/
public void removePackageItem(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String nodeRef = new NodeRef(Repository.getStoreRef(), params.get("id")).toString();
if (this.packageItemsToAdd != null && this.packageItemsToAdd.contains(nodeRef))
{
// remove the item from the added list if it was added in this dialog session
this.packageItemsToAdd.remove(nodeRef);
if (logger.isDebugEnabled())
logger.debug("Removed item from the added list: " + nodeRef);
}
else
{
// add the node to the list of items to remove
if (this.packageItemsToRemove == null)
{
this.packageItemsToRemove = new ArrayList<String>(1);
}
this.packageItemsToRemove.add(nodeRef);
if (logger.isDebugEnabled())
logger.debug("Added item to the removed list: " + nodeRef);
}
// reset the rich list so it re-renders
this.packageItemsRichList.setValue(null);
}
/**
* Toggles the complete flag for a workflow package item
*
* @param event The event containing a reference to the item to toggle the status for
*/
public void togglePackageItemComplete(ActionEvent event)
{
// TODO: implement this!
}
// ------------------------------------------------------------------------------
// Bean Getters and Setters
/**
* Returns a String array of NodeRef's that are being added to the workflow package
*
* @return String array of NodeRef's
*/
public String[] getItemsToAdd()
{
return this.itemsToAdd;
}
/**
* Sets the NodeRef's to add as items to the workflow package
*
* @param itemsToAdd NodeRef's to add to the workflow package
*/
public void setItemsToAdd(String[] itemsToAdd)
{
this.itemsToAdd = itemsToAdd;
}
/**
* Determines whether an item is currently being added to the workflow package
*
* @return true if an item is being added
*/
public boolean isItemBeingAdded()
{
return this.isItemBeingAdded;
}
/**
* Sets the rich list being used for the workflow package items
*
* @param richList The rich list instance
*/
public void setPackageItemsRichList(UIRichList richList)
{
this.packageItemsRichList = richList;
}
/**
* Returns the rich list being used for the workflow package items
*
* @return The rich list instance
*/
public UIRichList getPackageItemsRichList()
{
return this.packageItemsRichList;
}
/**
* Returns the Node representing the task
*
* @return The node
*/
public Node getTaskNode()
{
return this.taskNode;
}
/**
* Returns the WorkflowInstance that the current task belongs to
*
* @return The workflow instance
*/
public WorkflowInstance getWorkflowInstance()
{
return this.workflowInstance;
}
/**
* Returns the action group the current task uses for the workflow package
*
* @return action group id
*/
public String getPackageActionGroup()
{
return (String)this.task.properties.get(
WorkflowModel.PROP_PACKAGE_ACTION_GROUP);
}
/**
* Returns the action group the current task uses for each workflow package item
*
* @return action group id
*/
public String getPackageItemActionGroup()
{
return (String)this.task.properties.get(
WorkflowModel.PROP_PACKAGE_ITEM_ACTION_GROUP);
}
/**
* Returns a list of resources associated with this task
* i.e. the children of the workflow package
*
* @return The list of nodes
*/
public List<Node> getResources()
{
this.resources = new ArrayList<Node>(4);
if (this.workflowPackage != null)
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context, true);
tx.begin();
// get existing workflow package items
List<ChildAssociationRef> childRefs = this.nodeService.getChildAssocs(
this.workflowPackage, ContentModel.ASSOC_CONTAINS,
RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref: childRefs)
{
// create our Node representation from the NodeRef
NodeRef nodeRef = ref.getChildRef();
if (this.nodeService.exists(nodeRef))
{
// find it's type so we can see if it's a node we are interested in
QName type = this.nodeService.getType(nodeRef);
// make sure the type is defined in the data dictionary
TypeDefinition typeDef = this.dictionaryService.getType(type);
if (typeDef != null)
{
// look for content nodes or links to content
// NOTE: folders within workflow packages are ignored for now
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
ContentModel.TYPE_FILELINK.equals(type))
{
// if the node is not in the removed list then add create the
// client side representation and add to the list
if (this.packageItemsToRemove == null ||
this.packageItemsToRemove.contains(nodeRef.toString()) == false)
{
createAndAddNode(nodeRef);
}
}
}
else
{
if (logger.isWarnEnabled())
logger.warn("Found invalid object in database: id = " + nodeRef + ", type = " + type);
}
}
else
{
if (logger.isDebugEnabled())
logger.debug("Ignoring " + nodeRef + " as it has been removed from the repository");
}
}
// now iterate through the items to add list and add them to the list of resources
if (this.packageItemsToAdd != null)
{
for (String newItem : this.packageItemsToAdd)
{
NodeRef nodeRef = new NodeRef(newItem);
if (this.nodeService.exists(nodeRef))
{
// we know the type is correct as this was added as a result of a query
// for all content items so just add the item to the resources list
createAndAddNode(nodeRef);
}
else
{
if (logger.isDebugEnabled())
logger.debug("Ignoring " + nodeRef + " as it has been removed from the repository");
}
}
}
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
this.resources = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
else if (logger.isDebugEnabled())
{
logger.debug("Failed to find workflow package for task: " + this.task.id);
}
return this.resources;
}
/**
* Sets the workflow service to use
*
* @param workflowService
* WorkflowService instance
*/
public void setWorkflowService(WorkflowService workflowService)
{
this.workflowService = workflowService;
}
// ------------------------------------------------------------------------------
// Helper methods
protected void createAndAddNode(NodeRef nodeRef)
{
// create our Node representation
MapNode node = new MapNode(nodeRef, this.nodeService, true);
this.browseBean.setupCommonBindingProperties(node);
// add property resolvers to show path information
node.addPropertyResolver("path", this.browseBean.resolverPath);
node.addPropertyResolver("displayPath", this.browseBean.resolverDisplayPath);
// add a property resolver to indicate whether the item has been completed or not
// node.addPropertyResolver("completed", this.completeResolver);
this.resources.add(node);
}
// ------------------------------------------------------------------------------
// Inner classes
/**
* Property resolver to determine if the given node has been flagged as complete
*/
protected class TaskCompleteResolver implements NodePropertyResolver
{
public Object get(Node node)
{
String result = Application.getMessage(FacesContext.getCurrentInstance(), "no");
List<NodeRef> completedItems = (List<NodeRef>)task.properties.get(
WorkflowModel.PROP_COMPLETED_ITEMS);
if (completedItems != null && completedItems.size() > 0 &&
completedItems.contains(node.getNodeRef()))
{
result = Application.getMessage(FacesContext.getCurrentInstance(), "yes");
}
return result;
}
}
}

View File

@@ -1,476 +0,0 @@
package org.alfresco.web.bean.workflow;
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.faces.event.ActionEvent;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
import org.alfresco.service.cmr.workflow.WorkflowTransition;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.dialog.BaseDialogBean;
import org.alfresco.web.bean.repository.MapNode;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.NodePropertyResolver;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.TransientNode;
import org.alfresco.web.config.DialogsConfigElement.DialogButtonConfig;
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.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Bean implementation for the "Manage WorkItem" dialog.
*
* @author gavinc
*/
public class ManageWorkItemDialog extends BaseDialogBean
{
protected WorkflowService workflowService;
protected Node workItemNode;
protected WorkflowTask workItem;
protected WorkflowTransition[] transitions;
protected List<Node> resources;
protected WorkItemCompleteResolver completeResolver = new WorkItemCompleteResolver();
protected UIRichList packageItemsRichList;
protected static final String ID_PREFIX = "transition_";
protected static final String CLIENT_ID_PREFIX = "dialog:" + ID_PREFIX;
private static final Log logger = LogFactory.getLog(ManageWorkItemDialog.class);
// ------------------------------------------------------------------------------
// Dialog implementation
@Override
public void init(Map<String, String> parameters)
{
super.init(parameters);
String taskId = this.parameters.get("id");
this.workItem = this.workflowService.getTaskById(taskId);
if (this.workItem != null)
{
// setup a transient node to represent the work item we're managing
WorkflowTaskDefinition taskDef = this.workItem.definition;
this.workItemNode = new TransientNode(taskDef.metadata.getName(),
"task_" + System.currentTimeMillis(), this.workItem.properties);
}
}
@Override
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
if (logger.isDebugEnabled())
logger.debug("Saving work item: " + this.workItemNode.getId());
// prepare the edited parameters for saving
Map<QName, Serializable> params = WorkflowBean.prepareWorkItemParams(this.workItemNode);
// update the task with the updated parameters
this.workflowService.updateTask(this.workItem.id, params, null, null);
return outcome;
}
@Override
public List<DialogButtonConfig> getAdditionalButtons()
{
List<DialogButtonConfig> buttons = null;
if (this.workItem != null)
{
// get the transitions available from this work item and
// show them in the dialog as additional buttons
this.transitions = this.workItem.path.node.transitions;
if (this.transitions != null)
{
buttons = new ArrayList<DialogButtonConfig>(this.transitions.length);
for (WorkflowTransition trans : this.transitions)
{
buttons.add(new DialogButtonConfig(ID_PREFIX + trans.title, trans.title, null,
"#{DialogManager.bean.transition}", "false", null));
}
}
}
return buttons;
}
@Override
public String getFinishButtonLabel()
{
return Application.getMessage(FacesContext.getCurrentInstance(), "save");
}
@Override
public boolean getFinishButtonDisabled()
{
return false;
}
// ------------------------------------------------------------------------------
// Event handlers
@SuppressWarnings("unused")
public String transition()
{
String outcome = getDefaultFinishOutcome();
if (logger.isDebugEnabled())
logger.debug("Transitioning work item: " + this.workItemNode.getId());
// to find out which transition button was pressed we need
// to look for the button's id in the request parameters,
// the first non-null result is the button that was pressed.
FacesContext context = FacesContext.getCurrentInstance();
Map reqParams = context.getExternalContext().getRequestParameterMap();
String selectedTransition = null;
for (WorkflowTransition trans : this.transitions)
{
Object result = reqParams.get(CLIENT_ID_PREFIX + trans.title);
if (result != null)
{
// this was the button that was pressed
selectedTransition = trans.id;
break;
}
}
if (selectedTransition != null)
{
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(context);
tx.begin();
// prepare the edited parameters for saving
Map<QName, Serializable> params = WorkflowBean.prepareWorkItemParams(this.workItemNode);
// update the task with the updated parameters
this.workflowService.updateTask(this.workItem.id, params, null, null);
// signal the selected transition to the workflow task
this.workflowService.endTask(this.workItem.id, selectedTransition);
// commit the changes
tx.commit();
if (logger.isDebugEnabled())
logger.debug("Ended work item with transition: " + selectedTransition);
}
catch (Throwable e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(formatErrorMessage(e), e);
outcome = this.getErrorOutcome(e);
}
}
return outcome;
}
/**
* Removes an item from the workflow package
*
* @param event The event containing a reference to the item to remove
*/
public void removePackageItem(ActionEvent event)
{
logger.info("remove package item: " + event);
}
/**
* Toggles the complete flag for a workflow package item
*
* @param event The event containing a reference to the item to toggle the status for
*/
public void togglePackageItemComplete(ActionEvent event)
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
// create the node ref for the item we are toggling
NodeRef nodeRef = new NodeRef(Repository.getStoreRef(),
(String)params.get("id"));
// get the existing list of completed items
List<NodeRef> completedItems = (List<NodeRef>)this.workItem.properties.get(
WorkflowModel.PROP_COMPLETED_ITEMS);
if (completedItems == null)
{
// if it doesn't exist yet create the list and add the noderef
completedItems = new ArrayList<NodeRef>(1);
completedItems.add(nodeRef);
this.workItem.properties.put(WorkflowModel.PROP_COMPLETED_ITEMS,
(Serializable)completedItems);
}
else
{
if (completedItems.contains(nodeRef))
{
// the item is already in the list remove it
completedItems.remove(nodeRef);
// NOTE: There is a bug somwehere which causes the list to be
// returned as a byte array instead of a list if an empty
// list is persisted, therefore if the list is now empty
// set the completed items back to null
if (completedItems.size() == 0)
{
this.workItem.properties.put(WorkflowModel.PROP_COMPLETED_ITEMS, null);
}
}
else
{
// the noderef is not in the list yet so just add it
completedItems.add(nodeRef);
}
}
// update the task with the updated parameters
this.workflowService.updateTask(this.workItem.id, this.workItem.properties,
null, null);
// commit the transaction
tx.commit();
// reset the rich list if the change was successful
this.packageItemsRichList.setValue(null);
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
this.resources = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
// ------------------------------------------------------------------------------
// Bean Getters and Setters
/**
* Sets the rich list being used for the workflow package items
*
* @param richList The rich list instance
*/
public void setPackageItemsRichList(UIRichList richList)
{
this.packageItemsRichList = richList;
}
/**
* Returns the rich list being used for the workflow package items
*
* @return The rich list instance
*/
public UIRichList getPackageItemsRichList()
{
return this.packageItemsRichList;
}
/**
* Returns the Node representing the work item
*
* @return The node
*/
public Node getWorkItemNode()
{
return this.workItemNode;
}
/**
* Returns the action group the current task uses for the workflow package
*
* @return action group id
*/
public String getPackageActionGroup()
{
return (String)this.workItem.properties.get(
WorkflowModel.PROP_PACKAGE_ACTION_GROUP);
}
/**
* Returns the action group the current task uses for each workflow package item
*
* @return action group id
*/
public String getPackageItemActionGroup()
{
return (String)this.workItem.properties.get(
WorkflowModel.PROP_PACKAGE_ITEM_ACTION_GROUP);
}
/**
* Returns a list of resources associated with this work item
* i.e. the children of the workflow package
*
* @return The list of nodes
*/
public List<Node> getResources()
{
NodeRef workflowPackage = null;
Serializable obj = this.workItem.properties.get(WorkflowModel.ASSOC_PACKAGE);
// TODO: remove this workaroud where JBPM may return a String and not the NodeRef
if (obj instanceof NodeRef)
{
workflowPackage = (NodeRef)obj;
}
else if (obj instanceof String)
{
workflowPackage = new NodeRef((String)obj);
}
this.resources = new ArrayList<Node>(4);
if (workflowPackage != null)
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context, true);
tx.begin();
if (logger.isDebugEnabled())
logger.debug("Found workflow package for work item '" +
this.workItem.id + "': " + workflowPackage );
List<ChildAssociationRef> childRefs = this.nodeService.getChildAssocs(workflowPackage,
ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref: childRefs)
{
// create our Node representation from the NodeRef
NodeRef nodeRef = ref.getChildRef();
if (this.nodeService.exists(nodeRef))
{
// find it's type so we can see if it's a node we are interested in
QName type = this.nodeService.getType(nodeRef);
// make sure the type is defined in the data dictionary
TypeDefinition typeDef = this.dictionaryService.getType(type);
if (typeDef != null)
{
// look for content nodes or links to content
// NOTE: folders within workflow packages are ignored for now
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
ContentModel.TYPE_FILELINK.equals(type))
{
// create our Node representation
MapNode node = new MapNode(nodeRef, this.nodeService, true);
this.browseBean.setupCommonBindingProperties(node);
// add property resolvers to show path information
node.addPropertyResolver("path", this.browseBean.resolverPath);
node.addPropertyResolver("displayPath", this.browseBean.resolverDisplayPath);
// add a property resolver to indicate whether the item has been completed or not
node.addPropertyResolver("completed", this.completeResolver);
this.resources.add(node);
}
}
else
{
if (logger.isWarnEnabled())
logger.warn("Found invalid object in database: id = " + nodeRef + ", type = " + type);
}
}
}
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
this.resources = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
else if (logger.isDebugEnabled())
{
logger.debug("Failed to find workflow package for work item: " + this.workItem.id);
}
return this.resources;
}
/**
* Sets the workflow service to use
*
* @param workflowService
* WorkflowService instance
*/
public void setWorkflowService(WorkflowService workflowService)
{
this.workflowService = workflowService;
}
// ------------------------------------------------------------------------------
// Helper methods
// ------------------------------------------------------------------------------
// Inner classes
/**
* Property resolver to determine if the given node has been flagged as complete
*/
protected class WorkItemCompleteResolver implements NodePropertyResolver
{
public Object get(Node node)
{
String result = Application.getMessage(FacesContext.getCurrentInstance(), "no");
List<NodeRef> completedItems = (List<NodeRef>)workItem.properties.get(
WorkflowModel.PROP_COMPLETED_ITEMS);
if (completedItems != null && completedItems.size() > 0 &&
completedItems.contains(node.getNodeRef()))
{
result = Application.getMessage(FacesContext.getCurrentInstance(), "yes");
}
return result;
}
}
}

View File

@@ -0,0 +1,199 @@
package org.alfresco.web.bean.workflow;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
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.PersonService;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.dialog.BaseDialogBean;
import org.alfresco.web.bean.repository.Repository;
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;
/**
* Bean implementation for the "Reassign Task" dialog
*
* @author gavinc
*/
public class ReassignTaskDialog extends BaseDialogBean
{
protected String taskId;
protected WorkflowService workflowService;
protected PersonService personService;
private static final Log logger = LogFactory.getLog(ReassignTaskDialog.class);
// ------------------------------------------------------------------------------
// Dialog implementation
@Override
public void init(Map<String, String> parameters)
{
super.init(parameters);
this.taskId = this.parameters.get("task-id");
if (this.taskId == null || this.taskId.length() == 0)
{
throw new IllegalArgumentException("Reassign task dialog called without task id");
}
}
@Override
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
if (logger.isDebugEnabled())
logger.debug("Reassigning task with id: " + this.taskId);
UIComponent picker = context.getViewRoot().findComponent("dialog:dialog-body:user-picker");
if (picker != null && picker instanceof UIGenericPicker)
{
UIGenericPicker userPicker = (UIGenericPicker)picker;
String[] user = userPicker.getSelectedResults();
if (user != null && user.length > 0)
{
// create a map to hold the new owner property then update the task
String userName = user[0];
Map<QName, Serializable> params = new HashMap<QName, Serializable>(1);
params.put(ContentModel.PROP_OWNER, userName);
this.workflowService.updateTask(this.taskId, params, null, null);
}
else
{
if (logger.isWarnEnabled())
logger.warn("Failed to find selected user, reassign was unsuccessful");
}
}
else
{
if (logger.isWarnEnabled())
logger.warn("Failed to find user-picker component, reassign was unsuccessful");
}
if (logger.isDebugEnabled())
logger.debug("Reassigning task with id: " + this.taskId);
return outcome;
}
@Override
protected String getErrorMessageId()
{
return "error_reassign_task";
}
// ------------------------------------------------------------------------------
// Bean Getters and Setters
/**
* 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("users"))};
}
/**
* 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();
// 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;
}
Arrays.sort(items);
// commit the transaction
tx.commit();
}
catch (Throwable 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;
}
/**
* Sets the workflow service to use
*
* @param workflowService The WorkflowService instance
*/
public void setWorkflowService(WorkflowService workflowService)
{
this.workflowService = workflowService;
}
/**
* @param permissionService The PermissionService to set.
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
}

View File

@@ -1,14 +1,18 @@
package org.alfresco.web.bean.workflow;
import java.io.Serializable;
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.ResourceBundle;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.workflow.WorkflowModel;
@@ -23,10 +27,14 @@ import org.alfresco.service.cmr.workflow.WorkflowTaskState;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
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.TransientNode;
import org.alfresco.web.bean.wizard.BaseWizardBean;
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.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -42,6 +50,11 @@ public class StartWorkflowWizard extends BaseWizardBean
protected Map<String, WorkflowDefinition> workflows;
protected WorkflowService workflowService;
protected Node startTaskNode;
protected List<Node> resources;
protected List<String> packageItemsToAdd;
protected UIRichList packageItemsRichList;
protected String[] itemsToAdd;
protected boolean isItemBeingAdded = false;
protected boolean nextButtonDisabled = false;
private static final Log logger = LogFactory.getLog(StartWorkflowWizard.class);
@@ -65,6 +78,43 @@ public class StartWorkflowWizard extends BaseWizardBean
}
this.startTaskNode = null;
this.resources = null;
this.itemsToAdd = null;
this.packageItemsToAdd = new ArrayList<String>();
this.isItemBeingAdded = false;
if (this.packageItemsRichList != null)
{
this.packageItemsRichList.setValue(null);
this.packageItemsRichList = null;
}
// TODO: Does this need to be in a read-only transaction??
// add the item the workflow wizard was started on to the list of resources
String itemToWorkflowId = this.parameters.get("item-to-workflow");
if (itemToWorkflowId != null && itemToWorkflowId.length() > 0)
{
// create the node ref for the item and determine its type
NodeRef itemToWorkflow = new NodeRef(Repository.getStoreRef(), itemToWorkflowId);
QName type = this.nodeService.getType(itemToWorkflow);
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
this.dictionaryService.isSubClass(type, ContentModel.TYPE_FILELINK))
{
this.packageItemsToAdd.add(itemToWorkflow.toString());
}
}
}
@Override
public void restored()
{
// reset the workflow package rich list so everything gets re-evaluated
if (this.packageItemsRichList != null)
{
this.packageItemsRichList.setValue(null);
this.packageItemsRichList = null;
}
}
@Override
@@ -77,26 +127,23 @@ public class StartWorkflowWizard extends BaseWizardBean
logger.debug("Starting workflow: " + this.selectedWorkflow);
// prepare the parameters from the current state of the property sheet
Map<QName, Serializable> params = WorkflowBean.prepareWorkItemParams(this.startTaskNode);
Map<QName, Serializable> params = WorkflowBean.prepareTaskParams(this.startTaskNode);
if (logger.isDebugEnabled())
logger.debug("Starting workflow with parameters: " + params);
// create a workflow package for the attached items and add them
String itemToWorkflowId = this.parameters.get("item-to-workflow");
if (itemToWorkflowId != null && itemToWorkflowId.length() > 0)
if (this.packageItemsToAdd.size() > 0)
{
// create the node ref for the item and determine its type
NodeRef itemToWorkflow = new NodeRef(Repository.getStoreRef(), itemToWorkflowId);
QName type = this.nodeService.getType(itemToWorkflow);
NodeRef workflowPackage = this.workflowService.createPackage(null);
NodeRef workflowPackage = null;
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
this.dictionaryService.isSubClass(type, ContentModel.TYPE_FILELINK))
for (String addedItem : this.packageItemsToAdd)
{
// create a workflow package and add the given item to workflow as a child
workflowPackage = this.workflowService.createPackage(null);
this.nodeService.addChild(workflowPackage, itemToWorkflow,
NodeRef addedNodeRef = new NodeRef(addedItem);
this.nodeService.addChild(workflowPackage, addedNodeRef,
ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
QName.createValidLocalName((String)this.nodeService.getProperty(
itemToWorkflow, ContentModel.PROP_NAME))));
addedNodeRef, ContentModel.PROP_NAME))));
}
// add the workflow package to the parameter map
@@ -175,9 +222,131 @@ public class StartWorkflowWizard extends BaseWizardBean
return this.nextButtonDisabled;
}
// ------------------------------------------------------------------------------
// Event Handlers
/**
* Prepares the dialog to allow the user to add an item to the workflow package
*
* @param event The event
*/
public void prepareForAdd(ActionEvent event)
{
this.isItemBeingAdded = true;
}
/**
* Cancels the adding of an item to the workflow package
*
* @param event The event
*/
public void cancelAddPackageItems(ActionEvent event)
{
this.isItemBeingAdded = false;
}
/**
* Adds items to the workflow package
*
* @param event The event
*/
public void addPackageItems(ActionEvent event)
{
if (this.itemsToAdd != null)
{
for (String item : this.itemsToAdd)
{
this.packageItemsToAdd.add(item);
if (logger.isDebugEnabled())
logger.debug("Added item to the added list: " + item);
}
// reset the rich list so it re-renders
this.packageItemsRichList.setValue(null);
}
this.isItemBeingAdded = false;
this.itemsToAdd = null;
}
/**
* Removes an item from the workflow package
*
* @param event The event containing a reference to the item to remove
*/
public void removePackageItem(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String nodeRef = new NodeRef(Repository.getStoreRef(), params.get("id")).toString();
if (this.packageItemsToAdd.contains(nodeRef))
{
// remove the item from the added list if it was added in this dialog session
this.packageItemsToAdd.remove(nodeRef);
if (logger.isDebugEnabled())
logger.debug("Removed item from the added list: " + nodeRef);
}
// reset the rich list so it re-renders
this.packageItemsRichList.setValue(null);
}
// ------------------------------------------------------------------------------
// Bean Getters and Setters
/**
* Returns a String array of NodeRef's that are being added to the workflow package
*
* @return String array of NodeRef's
*/
public String[] getItemsToAdd()
{
return this.itemsToAdd;
}
/**
* Sets the NodeRef's to add as items to the workflow package
*
* @param itemsToAdd NodeRef's to add to the workflow package
*/
public void setItemsToAdd(String[] itemsToAdd)
{
this.itemsToAdd = itemsToAdd;
}
/**
* Determines whether an item is currently being added to the workflow package
*
* @return true if an item is being added
*/
public boolean isItemBeingAdded()
{
return this.isItemBeingAdded;
}
/**
* Sets the rich list being used for the workflow package items
*
* @param richList The rich list instance
*/
public void setPackageItemsRichList(UIRichList richList)
{
this.packageItemsRichList = richList;
}
/**
* Returns the rich list being used for the workflow package items
*
* @return The rich list instance
*/
public UIRichList getPackageItemsRichList()
{
return this.packageItemsRichList;
}
/**
* Returns the workflow selected by the user
*
@@ -317,6 +486,59 @@ public class StartWorkflowWizard extends BaseWizardBean
return availableWorkflows;
}
/**
* Returns a list of resources associated with this task
* i.e. the children of the workflow package
*
* @return The list of nodes
*/
public List<Node> getResources()
{
this.resources = new ArrayList<Node>(4);
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context, true);
tx.begin();
for (String newItem : this.packageItemsToAdd)
{
NodeRef nodeRef = new NodeRef(newItem);
if (this.nodeService.exists(nodeRef))
{
// create our Node representation
MapNode node = new MapNode(nodeRef, this.nodeService, true);
this.browseBean.setupCommonBindingProperties(node);
// add property resolvers to show path information
node.addPropertyResolver("path", this.browseBean.resolverPath);
node.addPropertyResolver("displayPath", this.browseBean.resolverDisplayPath);
this.resources.add(node);
}
else
{
if (logger.isDebugEnabled())
logger.debug("Ignoring " + nodeRef + " as it has been removed from the repository");
}
}
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
this.resources = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
return this.resources;
}
/**
* Sets the workflow service to use
*

View File

@@ -0,0 +1,48 @@
package org.alfresco.web.bean.workflow;
import java.util.List;
import javax.faces.context.FacesContext;
import org.alfresco.web.app.Application;
import org.alfresco.web.config.DialogsConfigElement.DialogButtonConfig;
/**
* Bean implementation for the "View Completed Task" dialog.
*
* @author gavinc
*/
public class ViewCompletedTaskDialog extends ManageTaskDialog
{
// ------------------------------------------------------------------------------
// Dialog implementation
@Override
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
// nothing to do as the finish button is not shown and the dialog is read only
return outcome;
}
@Override
public String getCancelButtonLabel()
{
return Application.getMessage(FacesContext.getCurrentInstance(), "close");
}
@Override
public List<DialogButtonConfig> getAdditionalButtons()
{
return null;
}
@Override
public String getTitle()
{
String titleStart = Application.getMessage(FacesContext.getCurrentInstance(), "view_completed_task_title");
return titleStart + ": " + this.task.title;
}
}

View File

@@ -39,8 +39,8 @@ public class WorkflowBean
{
protected NodeService nodeService;
protected WorkflowService workflowService;
protected List<Node> workItems;
protected List<Node> completedWorkItems;
protected List<Node> tasks;
protected List<Node> completedTasks;
private static final Log logger = LogFactory.getLog(WorkflowBean.class);
@@ -48,12 +48,12 @@ public class WorkflowBean
// Bean Getters and Setters
/**
* Returns a list of nodes representing the to do work items the
* Returns a list of nodes representing the to do tasks the
* current user has.
*
* @return List of to do work items
* @return List of to do tasks
*/
public List<Node> getWorkItemsToDo()
public List<Node> getTasksToDo()
{
// get the current username
FacesContext context = FacesContext.getCurrentInstance();
@@ -71,14 +71,14 @@ public class WorkflowBean
userName, WorkflowTaskState.IN_PROGRESS);
// create a list of transient nodes to represent
this.workItems = new ArrayList<Node>(tasks.size());
this.tasks = new ArrayList<Node>(tasks.size());
for (WorkflowTask task : tasks)
{
Node node = createWorkItem(task);
this.workItems.add(node);
Node node = createTask(task);
this.tasks.add(node);
if (logger.isDebugEnabled())
logger.debug("Added to do work item: " + node);
logger.debug("Added to do task: " + node);
}
// commit the changes
@@ -88,19 +88,19 @@ public class WorkflowBean
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage("Failed to get to do work items: " + e.toString(), e);
Utils.addErrorMessage("Failed to get to do tasks: " + e.toString(), e);
}
return this.workItems;
return this.tasks;
}
/**
* Returns a list of nodes representing the completed work items the
* Returns a list of nodes representing the completed tasks the
* current user has.
*
* @return List of completed work items
* @return List of completed tasks
*/
public List<Node> getWorkItemsCompleted()
public List<Node> getTasksCompleted()
{
// get the current username
FacesContext context = FacesContext.getCurrentInstance();
@@ -118,14 +118,14 @@ public class WorkflowBean
userName, WorkflowTaskState.COMPLETED);
// create a list of transient nodes to represent
this.completedWorkItems = new ArrayList<Node>(tasks.size());
this.completedTasks = new ArrayList<Node>(tasks.size());
for (WorkflowTask task : tasks)
{
Node node = createWorkItem(task);
this.completedWorkItems.add(node);
Node node = createTask(task);
this.completedTasks.add(node);
if (logger.isDebugEnabled())
logger.debug("Added completed work item: " + node);
logger.debug("Added completed task: " + node);
}
// commit the changes
@@ -135,10 +135,10 @@ public class WorkflowBean
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage("Failed to get completed work items: " + e.toString(), e);
Utils.addErrorMessage("Failed to get completed tasks: " + e.toString(), e);
}
return this.completedWorkItems;
return this.completedTasks;
}
/**
@@ -164,7 +164,7 @@ public class WorkflowBean
// ------------------------------------------------------------------------------
// Helper methods
public static Map<QName, Serializable> prepareWorkItemParams(Node node)
public static Map<QName, Serializable> prepareTaskParams(Node node)
{
Map<QName, Serializable> params = new HashMap<QName, Serializable>();
@@ -199,9 +199,6 @@ public class WorkflowBean
params.put(assocQName, (Serializable)targets);
}
if (logger.isDebugEnabled())
logger.debug("Prepared parameters: " + params);
return params;
}
@@ -211,7 +208,7 @@ public class WorkflowBean
*
* @param task The task to create a representation of
*/
protected TransientMapNode createWorkItem(WorkflowTask task)
protected TransientMapNode createTask(WorkflowTask task)
{
// get the type of the task
WorkflowTaskDefinition taskDef = task.definition;