mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
. Workflow Command Servlet implementation
. Refactored common simple workflow code into a util class. . Example template that demonstrates both querying for workflow information on a document (useful anyway) and executes the servlet to perform both the Approve and Reject actions if appropriate for the document. . TemplateNode template API object now exposes the browse navigation servlet URL for a Space as the "url" API call . Fix long standing bug in UIRichList (since PR1!) - subtle behaviour issue where under very high server loads, the richlist component would render the wrong number of items per row. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2590 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
27
config/alfresco/templates/workflow_details.ftl
Normal file
27
config/alfresco/templates/workflow_details.ftl
Normal file
@@ -0,0 +1,27 @@
|
||||
<#if document?exists>
|
||||
<#if hasAspect(document, "app:simpleworkflow") = 1>
|
||||
This document has the following workflow:<br>
|
||||
<#if document.properties["app:approveStep"]?exists>
|
||||
<#assign ref=document.nodeRef>
|
||||
<#assign workspace=ref[0..ref?index_of("://")-1]>
|
||||
<#assign storenode=ref[ref?index_of("://")+3..]>
|
||||
Approve Step: <a href="/alfresco/workflow/approve/${workspace}/${storenode}">${document.properties["app:approveStep"]}</a><br>
|
||||
</#if>
|
||||
<#if document.properties["app:approveFolder"]?exists>
|
||||
Approve Folder: <a href="/alfresco${document.properties["app:approveFolder"].url}">${document.properties["app:approveFolder"].name}</a><br>
|
||||
</#if>
|
||||
<#if document.properties["app:rejectStep"]?exists>
|
||||
<#assign ref=document.nodeRef>
|
||||
<#assign workspace=ref[0..ref?index_of("://")-1]>
|
||||
<#assign storenode=ref[ref?index_of("://")+3..]>
|
||||
Reject Step: <a href="/alfresco/workflow/reject/${workspace}/${storenode}">${document.properties["app:rejectStep"]}</a><br>
|
||||
</#if>
|
||||
<#if document.properties["app:rejectFolder"]?exists>
|
||||
Reject Folder: <a href="/alfresco${document.properties["app:rejectFolder"].url}">{document.properties["app:rejectFolder"].name}</a><br>
|
||||
</#if>
|
||||
<#else>
|
||||
This document has no workflow.<br>
|
||||
</#if>
|
||||
<#else>
|
||||
No document found!
|
||||
</#if>
|
@@ -103,7 +103,7 @@ public class TemplateContentServlet extends BaseServlet
|
||||
int tokenCount = t.countTokens();
|
||||
if (tokenCount < 5)
|
||||
{
|
||||
throw new IllegalArgumentException("Download URL did not contain all required args: " + uri);
|
||||
throw new IllegalArgumentException("Template Servlet URL did not contain all required args: " + uri);
|
||||
}
|
||||
|
||||
t.nextToken(); // skip web app name
|
||||
|
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.web.app.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.web.bean.WorkflowUtil;
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Servlet responsible for executing workflow commands upon a node.
|
||||
* <p>
|
||||
* The URL to the servlet should be generated thus:
|
||||
* <pre>/alfresco/workflow/command/workspace/SpacesStore/0000-0000-0000-0000
|
||||
* <p>
|
||||
* The 'command' identifies the workflow action to execute upon the node (e.g. "approve" or "reject").
|
||||
* The store protocol, followed by the store ID, followed by the content Node Id used to
|
||||
* identify the node to execute the workflow action upon.
|
||||
* <p>
|
||||
* A 'return-page' URL argument can be specified as the redirect page to navigate too after processing.
|
||||
* <p>
|
||||
* Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
|
||||
* ?ticket=1234567890
|
||||
* <p>
|
||||
* And/or also followed by the "?guest=true" argument to force guest access login for the URL.
|
||||
*
|
||||
* @author Kevin Roast
|
||||
*/
|
||||
public class WorkflowActionServlet extends BaseServlet
|
||||
{
|
||||
private static final long serialVersionUID = -3111407921997365999L;
|
||||
|
||||
private static Log logger = LogFactory.getLog(WorkflowActionServlet.class);
|
||||
|
||||
private static CommandFactory commandfactory = CommandFactory.getInstance();
|
||||
|
||||
public static final String ARG_RETURNPAGE = "return-page";
|
||||
|
||||
public static final String CMD_APPROVE = "approve";
|
||||
public static final String CMD_REJECT = "reject";
|
||||
|
||||
private static final String DEFAULT_URL = "/workflow/{0}/{1}/{2}/{3}";
|
||||
private static final String RETURN_URL = "/workflow/{0}/{1}/{2}/{3}?" + ARG_RETURNPAGE + "={4}";
|
||||
|
||||
static
|
||||
{
|
||||
// register the available Workflow commands
|
||||
commandfactory.registerCommand(CMD_APPROVE, ApproveCommand.class);
|
||||
commandfactory.registerCommand(CMD_REJECT, RejectCommand.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
||||
*/
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse res)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
String uri = req.getRequestURI();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Processing URL: " + uri + (req.getQueryString() != null ? ("?" + req.getQueryString()) : ""));
|
||||
|
||||
AuthenticationStatus status = servletAuthenticate(req, res);
|
||||
if (status == AuthenticationStatus.Failure)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StringTokenizer t = new StringTokenizer(uri, "/");
|
||||
int tokenCount = t.countTokens();
|
||||
if (tokenCount < 5)
|
||||
{
|
||||
throw new IllegalArgumentException("Workflow Servlet URL did not contain all required args: " + uri);
|
||||
}
|
||||
|
||||
t.nextToken(); // skip web app name
|
||||
t.nextToken(); // skip servlet name
|
||||
|
||||
// get the command to perform e.g. "approve"
|
||||
String command = t.nextToken();
|
||||
|
||||
// get NodeRef to the node with the workflow attached to it
|
||||
StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
|
||||
NodeRef nodeRef = new NodeRef(storeRef, t.nextToken());
|
||||
|
||||
// get the services we need to execute the workflow command
|
||||
ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
|
||||
PermissionService permissionService = serviceRegistry.getPermissionService();
|
||||
|
||||
// check that the user has at least READ access on the node - else redirect to the login page
|
||||
if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED)
|
||||
{
|
||||
redirectToLoginPage(req, res, getServletContext());
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
UserTransaction txn = null;
|
||||
try
|
||||
{
|
||||
txn = serviceRegistry.getTransactionService().getUserTransaction();
|
||||
txn.begin();
|
||||
|
||||
// find the workflow command from the registered list of commands
|
||||
// the CommandFactory supplies use with an instance of the command to use
|
||||
Map<String, Object> properties = new HashMap<String, Object>(1, 1.0f);
|
||||
properties.put("target", nodeRef);
|
||||
Command cmd = commandfactory.createCommand(command, properties);
|
||||
if (cmd == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Unknown workflow command specified: " + command);
|
||||
}
|
||||
cmd.execute(serviceRegistry);
|
||||
|
||||
// commit the transaction
|
||||
txn.commit();
|
||||
}
|
||||
catch (Throwable txnErr)
|
||||
{
|
||||
try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
|
||||
throw txnErr;
|
||||
}
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
// TODO: could show error status output here instead of throwing an exception?
|
||||
throw new AlfrescoRuntimeException("Error during workflow servlet processing: " + err.getMessage(), err);
|
||||
}
|
||||
|
||||
String returnPage = req.getParameter(ARG_RETURNPAGE);
|
||||
if (returnPage != null && returnPage.length() != 0)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Redirecting to specified return page: " + returnPage);
|
||||
|
||||
res.sendRedirect(returnPage);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("No return page specified, displaying status output.");
|
||||
|
||||
res.setContentType("text/html");
|
||||
PrintWriter out = res.getWriter();
|
||||
out.print("Workflow command: '");
|
||||
out.print(command);
|
||||
out.print("' executed against node: ");
|
||||
out.println(nodeRef.toString());
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to generate a URL to process a workflow action against a node.
|
||||
* <p>
|
||||
* The result of the workflow action is supplied returned as the response.
|
||||
*
|
||||
* @param nodeRef NodeRef of the node to generate URL for (cannot be null)
|
||||
* @param action Workflow action (See constants) to execute on the node
|
||||
*
|
||||
* @return URL to process the workflow action
|
||||
*/
|
||||
public final static String generateURL(NodeRef nodeRef, String action)
|
||||
{
|
||||
return MessageFormat.format(DEFAULT_URL, new Object[] {
|
||||
action,
|
||||
nodeRef.getStoreRef().getProtocol(),
|
||||
nodeRef.getStoreRef().getIdentifier(),
|
||||
nodeRef.getId() } );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to generate a URL to process a workflow action against a node.
|
||||
* <p>
|
||||
* The result of the workflow action is supplied returned as the response.
|
||||
*
|
||||
* @param nodeRef NodeRef of the node to generate URL for (cannot be null)
|
||||
* @param action Workflow action (See constants) to execute on the node
|
||||
* @param returnPage Return page URL to redirect after success (e.g. /alfresco/navigate/browse)
|
||||
*
|
||||
* @return URL to process the workflow action
|
||||
*/
|
||||
public final static String generateURL(NodeRef nodeRef, String action, String returnPage)
|
||||
{
|
||||
try
|
||||
{
|
||||
return MessageFormat.format(RETURN_URL, new Object[] {
|
||||
action,
|
||||
nodeRef.getStoreRef().getProtocol(),
|
||||
nodeRef.getStoreRef().getIdentifier(),
|
||||
nodeRef.getId(),
|
||||
Utils.replace(URLEncoder.encode(returnPage, "UTF-8"), "+", "%20")} );
|
||||
}
|
||||
catch (UnsupportedEncodingException uee)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Failed to encode workflow URL for node: " + nodeRef, uee);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple command pattern interface
|
||||
*/
|
||||
interface Command
|
||||
{
|
||||
/**
|
||||
* Execute the command
|
||||
*
|
||||
* @param serviceRegistry The ServiceRegistry instance
|
||||
*/
|
||||
void execute(ServiceRegistry serviceRegistry);
|
||||
|
||||
/**
|
||||
* @param properties bag of named properties for the command
|
||||
*/
|
||||
void setProperties(Map<String, Object> properties);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base command class
|
||||
*/
|
||||
static abstract class BaseCommand implements Command
|
||||
{
|
||||
Map<String, Object> properties = Collections.<String, Object>emptyMap();
|
||||
|
||||
/**
|
||||
* @see org.alfresco.web.app.servlet.WorkflowActionServlet.Command#setProperties(java.util.Map)
|
||||
*/
|
||||
public void setProperties(Map<String, Object> properties)
|
||||
{
|
||||
if (properties != null)
|
||||
{
|
||||
this.properties = properties;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Approve Workflow command implementation
|
||||
*/
|
||||
static final class ApproveCommand extends BaseCommand
|
||||
{
|
||||
static final String PROP_TARGET = "target";
|
||||
|
||||
/**
|
||||
* @see org.alfresco.web.app.servlet.WorkflowActionServlet.Command#execute(org.alfresco.service.ServiceRegistry)
|
||||
*/
|
||||
public void execute(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
NodeRef nodeRef = (NodeRef)this.properties.get(PROP_TARGET);
|
||||
if (nodeRef == null)
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to execute ApproveCommand - mandatory parameter not supplied: " + PROP_TARGET);
|
||||
}
|
||||
|
||||
WorkflowUtil.approve(nodeRef, serviceRegistry.getNodeService(), serviceRegistry.getCopyService());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reject Workflow command implementation
|
||||
*/
|
||||
static final class RejectCommand extends BaseCommand
|
||||
{
|
||||
static final String PROP_TARGET = "target";
|
||||
|
||||
/**
|
||||
* @see org.alfresco.web.app.servlet.WorkflowActionServlet.Command#execute(org.alfresco.service.ServiceRegistry)
|
||||
*/
|
||||
public void execute(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
NodeRef nodeRef = (NodeRef)this.properties.get(PROP_TARGET);
|
||||
if (nodeRef == null)
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to execute RejectCommand - mandatory parameter not supplied: " + PROP_TARGET);
|
||||
}
|
||||
|
||||
WorkflowUtil.reject(nodeRef, serviceRegistry.getNodeService(), serviceRegistry.getCopyService());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Command Factory helper
|
||||
*/
|
||||
static final class CommandFactory
|
||||
{
|
||||
private static CommandFactory instance = new CommandFactory();
|
||||
|
||||
private static Map<String, Class> registry = new HashMap<String, Class>(4, 1.0f);
|
||||
|
||||
/**
|
||||
* Private constructor - protect the singleton instance
|
||||
*/
|
||||
private CommandFactory()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the singleton CommandFactory instance
|
||||
*/
|
||||
static CommandFactory getInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a command name against an implementation
|
||||
*
|
||||
* @param name Unique name of the command
|
||||
* @param clazz Class implementation of the command
|
||||
*/
|
||||
void registerCommand(String name, Class clazz)
|
||||
{
|
||||
registry.put(name, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a command instance of the specified command name
|
||||
*
|
||||
* @param name Name of the command to create (must be registered)
|
||||
*
|
||||
* @return the Command instance or null if not found
|
||||
*/
|
||||
Command createCommand(String name)
|
||||
{
|
||||
return createCommand(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a command instance of the specified command name
|
||||
*
|
||||
* @param name Name of the command to create (must be registered)
|
||||
* @param properties Bag of name/value properties to pass to command upon creation
|
||||
*
|
||||
* @return the Command instance or null if not found
|
||||
*/
|
||||
Command createCommand(String name, Map<String, Object> properties)
|
||||
{
|
||||
Command result = null;
|
||||
|
||||
// lookup command by name in the registry
|
||||
Class clazz = registry.get(name);
|
||||
if (clazz != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object obj = clazz.newInstance();
|
||||
if (obj instanceof Command)
|
||||
{
|
||||
result = (Command)obj;
|
||||
if (properties != null)
|
||||
{
|
||||
result.setProperties(properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
// return default if this occurs
|
||||
logger.warn("Unable to create workflow command instance '" + name +
|
||||
"' with classname '" + clazz.getName() + "' due to error: " + err.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@@ -40,7 +40,6 @@ import org.alfresco.service.cmr.repository.TemplateNode;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
import org.alfresco.service.cmr.version.VersionHistory;
|
||||
import org.alfresco.service.cmr.version.VersionService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.web.app.Application;
|
||||
import org.alfresco.web.app.context.UIContextService;
|
||||
@@ -662,18 +661,6 @@ public class DocumentDetailsBean extends BaseDetailsBean
|
||||
}
|
||||
|
||||
NodeRef docNodeRef = new NodeRef(Repository.getStoreRef(), id);
|
||||
Node docNode = new Node(docNodeRef);
|
||||
|
||||
if (docNode.hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW) == false)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("You can not approve a document that is not part of a workflow");
|
||||
}
|
||||
|
||||
// get the simple workflow aspect properties
|
||||
Map<String, Object> props = docNode.getProperties();
|
||||
|
||||
Boolean approveMove = (Boolean)props.get(ContentModel.PROP_APPROVE_MOVE.toString());
|
||||
NodeRef approveFolder = (NodeRef)props.get(ContentModel.PROP_APPROVE_FOLDER.toString());
|
||||
|
||||
UserTransaction tx = null;
|
||||
try
|
||||
@@ -681,23 +668,8 @@ public class DocumentDetailsBean extends BaseDetailsBean
|
||||
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
|
||||
tx.begin();
|
||||
|
||||
// first we need to take off the simpleworkflow aspect
|
||||
this.nodeService.removeAspect(docNodeRef, ContentModel.ASPECT_SIMPLE_WORKFLOW);
|
||||
|
||||
if (approveMove.booleanValue())
|
||||
{
|
||||
// move the document to the specified folder
|
||||
String qname = QName.createValidLocalName(docNode.getName());
|
||||
this.nodeService.moveNode(docNodeRef, approveFolder, ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname));
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy the document to the specified folder
|
||||
String qname = QName.createValidLocalName(docNode.getName());
|
||||
this.copyService.copy(docNodeRef, approveFolder, ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname));
|
||||
}
|
||||
// call the service to perform the approve
|
||||
WorkflowUtil.approve(docNodeRef, this.nodeService, this.copyService);
|
||||
|
||||
// commit the transaction
|
||||
tx.commit();
|
||||
@@ -710,13 +682,6 @@ public class DocumentDetailsBean extends BaseDetailsBean
|
||||
|
||||
// also make sure the UI will get refreshed
|
||||
UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
String movedCopied = approveMove ? "moved" : "copied";
|
||||
logger.debug("Document has been approved and " + movedCopied + " to folder with id of " +
|
||||
approveFolder.getId());
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
@@ -761,24 +726,6 @@ public class DocumentDetailsBean extends BaseDetailsBean
|
||||
}
|
||||
|
||||
NodeRef docNodeRef = new NodeRef(Repository.getStoreRef(), id);
|
||||
Node docNode = new Node(docNodeRef);
|
||||
|
||||
if (docNode.hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW) == false)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("You can not reject a document that is not part of a workflow");
|
||||
}
|
||||
|
||||
// get the simple workflow aspect properties
|
||||
Map<String, Object> props = docNode.getProperties();
|
||||
|
||||
String rejectStep = (String)props.get(ContentModel.PROP_REJECT_STEP.toString());
|
||||
Boolean rejectMove = (Boolean)props.get(ContentModel.PROP_REJECT_MOVE.toString());
|
||||
NodeRef rejectFolder = (NodeRef)props.get(ContentModel.PROP_REJECT_FOLDER.toString());
|
||||
|
||||
if (rejectStep == null && rejectMove == null && rejectFolder == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("The workflow does not have a reject step defined");
|
||||
}
|
||||
|
||||
UserTransaction tx = null;
|
||||
try
|
||||
@@ -786,23 +733,8 @@ public class DocumentDetailsBean extends BaseDetailsBean
|
||||
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
|
||||
tx.begin();
|
||||
|
||||
// first we need to take off the simpleworkflow aspect
|
||||
this.nodeService.removeAspect(docNodeRef, ContentModel.ASPECT_SIMPLE_WORKFLOW);
|
||||
|
||||
if (rejectMove.booleanValue())
|
||||
{
|
||||
// move the document to the specified folder
|
||||
String qname = QName.createValidLocalName(docNode.getName());
|
||||
this.nodeService.moveNode(docNodeRef, rejectFolder, ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname));
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy the document to the specified folder
|
||||
String qname = QName.createValidLocalName(docNode.getName());
|
||||
this.copyService.copy(docNodeRef, rejectFolder, ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname));
|
||||
}
|
||||
// call the service to perform the reject
|
||||
WorkflowUtil.reject(docNodeRef, this.nodeService, this.copyService);
|
||||
|
||||
// commit the transaction
|
||||
tx.commit();
|
||||
@@ -815,13 +747,6 @@ public class DocumentDetailsBean extends BaseDetailsBean
|
||||
|
||||
// also make sure the UI will get refreshed
|
||||
UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
String movedCopied = rejectMove ? "moved" : "copied";
|
||||
logger.debug("Document has been rejected and " + movedCopied + " to folder with id of " +
|
||||
rejectFolder.getId());
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
|
149
source/java/org/alfresco/web/bean/WorkflowUtil.java
Normal file
149
source/java/org/alfresco/web/bean/WorkflowUtil.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.Map;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.repository.CopyService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.web.bean.repository.Node;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Helper class for common Simple Workflow functionality.
|
||||
* <p>
|
||||
* This class should be replaced with calls to a WorkflowService once it is available.
|
||||
*
|
||||
* @author Kevin Roast
|
||||
*/
|
||||
public class WorkflowUtil
|
||||
{
|
||||
private static Logger logger = Logger.getLogger(WorkflowUtil.class);
|
||||
|
||||
/**
|
||||
* Execute the Approve step for the Simple Workflow on a node.
|
||||
*
|
||||
* @param ref NodeRef to the node with the workflow
|
||||
* @param nodeService NodeService instance
|
||||
* @param copyService CopyService instance
|
||||
*
|
||||
* @throws AlfrescoRuntimeException
|
||||
*/
|
||||
public static void approve(NodeRef ref, NodeService nodeService, CopyService copyService)
|
||||
throws AlfrescoRuntimeException
|
||||
{
|
||||
Node docNode = new Node(ref);
|
||||
|
||||
if (docNode.hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW) == false)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Cannot approve a document that is not part of a workflow.");
|
||||
}
|
||||
|
||||
// get the simple workflow aspect properties
|
||||
Map<String, Object> props = docNode.getProperties();
|
||||
|
||||
Boolean approveMove = (Boolean)props.get(ContentModel.PROP_APPROVE_MOVE.toString());
|
||||
NodeRef approveFolder = (NodeRef)props.get(ContentModel.PROP_APPROVE_FOLDER.toString());
|
||||
|
||||
// first we need to take off the simpleworkflow aspect
|
||||
nodeService.removeAspect(ref, ContentModel.ASPECT_SIMPLE_WORKFLOW);
|
||||
|
||||
if (approveMove.booleanValue())
|
||||
{
|
||||
// move the document to the specified folder
|
||||
String qname = QName.createValidLocalName(docNode.getName());
|
||||
nodeService.moveNode(ref, approveFolder, ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname));
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy the document to the specified folder
|
||||
String qname = QName.createValidLocalName(docNode.getName());
|
||||
copyService.copy(ref, approveFolder, ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname));
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
String movedCopied = approveMove ? "moved" : "copied";
|
||||
logger.debug("Document has been approved and " + movedCopied + " to folder with id of " +
|
||||
approveFolder.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the Reject step for the Simple Workflow on a node.
|
||||
*
|
||||
* @param ref NodeRef to the node with the workflow
|
||||
* @param nodeService NodeService instance
|
||||
* @param copyService CopyService instance
|
||||
*
|
||||
* @throws AlfrescoRuntimeException
|
||||
*/
|
||||
public static void reject(NodeRef ref, NodeService nodeService, CopyService copyService)
|
||||
throws AlfrescoRuntimeException
|
||||
{
|
||||
Node docNode = new Node(ref);
|
||||
|
||||
if (docNode.hasAspect(ContentModel.ASPECT_SIMPLE_WORKFLOW) == false)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Cannot reject a document that is not part of a workflow.");
|
||||
}
|
||||
|
||||
// get the simple workflow aspect properties
|
||||
Map<String, Object> props = docNode.getProperties();
|
||||
|
||||
String rejectStep = (String)props.get(ContentModel.PROP_REJECT_STEP.toString());
|
||||
Boolean rejectMove = (Boolean)props.get(ContentModel.PROP_REJECT_MOVE.toString());
|
||||
NodeRef rejectFolder = (NodeRef)props.get(ContentModel.PROP_REJECT_FOLDER.toString());
|
||||
|
||||
if (rejectStep == null && rejectMove == null && rejectFolder == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("The workflow does not have a reject step defined,");
|
||||
}
|
||||
|
||||
// first we need to take off the simpleworkflow aspect
|
||||
nodeService.removeAspect(ref, ContentModel.ASPECT_SIMPLE_WORKFLOW);
|
||||
|
||||
if (rejectMove.booleanValue())
|
||||
{
|
||||
// move the document to the specified folder
|
||||
String qname = QName.createValidLocalName(docNode.getName());
|
||||
nodeService.moveNode(ref, rejectFolder, ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname));
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy the document to the specified folder
|
||||
String qname = QName.createValidLocalName(docNode.getName());
|
||||
copyService.copy(ref, rejectFolder, ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname));
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
String movedCopied = rejectMove ? "moved" : "copied";
|
||||
logger.debug("Document has been rejected and " + movedCopied + " to folder with id of " +
|
||||
rejectFolder.getId());
|
||||
}
|
||||
}
|
||||
}
|
@@ -73,11 +73,11 @@ public class ClipboardBean
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeOperationsService The NodeOperationsService to set.
|
||||
* @param copyService The CopyService to set.
|
||||
*/
|
||||
public void setNodeOperationsService(CopyService nodeOperationsService)
|
||||
public void setCopyService(CopyService copyService)
|
||||
{
|
||||
this.nodeOperationsService = nodeOperationsService;
|
||||
this.copyService = copyService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -316,7 +316,7 @@ public class ClipboardBean
|
||||
}
|
||||
else
|
||||
{
|
||||
this.nodeOperationsService.copy(
|
||||
this.copyService.copy(
|
||||
item.Node.getNodeRef(),
|
||||
destRef,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
@@ -415,8 +415,8 @@ public class ClipboardBean
|
||||
/** The FileFolderService to be used by the bean */
|
||||
protected FileFolderService fileFolderService;
|
||||
|
||||
/** The NodeOperationsService to be used by the bean */
|
||||
protected CopyService nodeOperationsService;
|
||||
/** The CopyService to be used by the bean */
|
||||
protected CopyService copyService;
|
||||
|
||||
/** The NavigationBean reference */
|
||||
protected NavigationBean navigator;
|
||||
|
@@ -62,11 +62,10 @@ public class UIRichList extends UIComponentBase implements IDataContainer
|
||||
{
|
||||
Class clazz = Class.forName(view);
|
||||
IRichListRenderer renderer = (IRichListRenderer)clazz.newInstance();
|
||||
UIRichList.viewRenderers.put(renderer.getViewModeID(), renderer);
|
||||
viewRenderers.put(renderer.getViewModeID(), renderer);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Added view '" + renderer.getViewModeID() +
|
||||
"' to UIRichList");
|
||||
logger.debug("Added view '" + renderer.getViewModeID() + "' to UIRichList");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -449,7 +448,7 @@ public class UIRichList extends UIComponentBase implements IDataContainer
|
||||
IRichListRenderer renderer = null;
|
||||
if (getViewMode() != null)
|
||||
{
|
||||
renderer = (IRichListRenderer)UIRichList.viewRenderers.get(getViewMode());
|
||||
renderer = (IRichListRenderer)viewRenderers.get(getViewMode());
|
||||
}
|
||||
return renderer;
|
||||
}
|
||||
@@ -509,7 +508,7 @@ public class UIRichList extends UIComponentBase implements IDataContainer
|
||||
// Private data
|
||||
|
||||
/** map of available IRichListRenderer instances */
|
||||
private final static Map<String, IRichListRenderer> viewRenderers = new HashMap<String, IRichListRenderer>(5);
|
||||
private final Map<String, IRichListRenderer> viewRenderers = new HashMap<String, IRichListRenderer>(4, 1.0f);
|
||||
|
||||
// component state
|
||||
private int currentPage = 0;
|
||||
|
@@ -162,7 +162,7 @@
|
||||
<value>#{FileFolderService}</value>
|
||||
</managed-property>
|
||||
<managed-property>
|
||||
<property-name>nodeOperationsService</property-name>
|
||||
<property-name>copyService</property-name>
|
||||
<value>#{CopyService}</value>
|
||||
</managed-property>
|
||||
</managed-bean>
|
||||
|
@@ -150,6 +150,11 @@
|
||||
<servlet-class>org.alfresco.web.app.servlet.TemplateContentServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>workflowAction</servlet-name>
|
||||
<servlet-class>org.alfresco.web.app.servlet.WorkflowActionServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>axis</servlet-name>
|
||||
<servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>
|
||||
@@ -195,6 +200,11 @@
|
||||
<url-pattern>/template/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>workflowAction</servlet-name>
|
||||
<url-pattern>/workflow/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>axis</servlet-name>
|
||||
<url-pattern>/api/*</url-pattern>
|
||||
|
Reference in New Issue
Block a user