diff --git a/source/java/org/alfresco/web/action/ActionEvaluator.java b/source/java/org/alfresco/web/action/ActionEvaluator.java
index fc80f8acff..f27c177ca2 100644
--- a/source/java/org/alfresco/web/action/ActionEvaluator.java
+++ b/source/java/org/alfresco/web/action/ActionEvaluator.java
@@ -1,38 +1,38 @@
-package org.alfresco.web.action;
-
-import java.io.Serializable;
-
-import org.alfresco.web.bean.repository.Node;
-
-/**
- * Contract supported by all classes that provide dynamic evaluation for a UI action.
- *
- * Evaluators are supplied with a Node instance context object.
- *
- * The evaluator should decide if the action precondition is valid based on the appropriate
- * logic and the properties etc. of the Node context and return the result.
- *
- * @author Kevin Roast
- */
-public interface ActionEvaluator extends Serializable
-{
- /**
- * The evaluator should decide if the action precondition is valid based on the appropriate
- * logic and the properties etc. of the Node context and return the result.
- *
- * @param node Node context for the action
- *
- * @return result of whether the action can proceed.
- */
- public boolean evaluate(Node node);
-
- /**
- * The evaluator should decide if the action precondition is valid based on the appropriate
- * logic and the state etc. of the given object and return the result.
- *
- * @param obj The object the action is for
- *
- * @return result of whether the action can proceed.
- */
- public boolean evaluate(Object obj);
-}
+package org.alfresco.web.action;
+
+import java.io.Serializable;
+
+import org.alfresco.web.bean.repository.Node;
+
+/**
+ * Contract supported by all classes that provide dynamic evaluation for a UI action.
+ *
+ * Evaluators are supplied with a Node instance context object.
+ *
+ * The evaluator should decide if the action precondition is valid based on the appropriate
+ * logic and the properties etc. of the Node context and return the result.
+ *
+ * @author Kevin Roast
+ */
+public interface ActionEvaluator extends Serializable
+{
+ /**
+ * The evaluator should decide if the action precondition is valid based on the appropriate
+ * logic and the properties etc. of the Node context and return the result.
+ *
+ * @param node Node context for the action
+ *
+ * @return result of whether the action can proceed.
+ */
+ public boolean evaluate(Node node);
+
+ /**
+ * The evaluator should decide if the action precondition is valid based on the appropriate
+ * logic and the state etc. of the given object and return the result.
+ *
+ * @param obj The object the action is for
+ *
+ * @return result of whether the action can proceed.
+ */
+ public boolean evaluate(Object obj);
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/ApproveDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/ApproveDocEvaluator.java
index e540efeb87..d6986bd950 100644
--- a/source/java/org/alfresco/web/action/evaluator/ApproveDocEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/ApproveDocEvaluator.java
@@ -1,34 +1,34 @@
-package org.alfresco.web.action.evaluator;
-
-import java.util.Map;
-
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.web.bean.repository.Node;
-
-/**
- * UI Action Evaluator - 'Approve' workflow step for document or space.
- *
- * @author Kevin Roast
- */
-public class ApproveDocEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = 2958297435415449179L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- Map properties = node.getProperties();
-
- Boolean approveMove = (Boolean) properties.get("app:approveMove");
- boolean isMove = approveMove == null ? false : approveMove;
-
- boolean canProceed = (properties.get("app:approveStep") != null) && !node.isLocked();
- //If this approval is going to result in a move of the node then we check whether the user
- //has permission. The delete permission is required in order to move a node (odd, perhaps, but true).
- canProceed &= (!isMove || node.hasPermission(PermissionService.DELETE));
-
- return canProceed;
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import java.util.Map;
+
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.web.bean.repository.Node;
+
+/**
+ * UI Action Evaluator - 'Approve' workflow step for document or space.
+ *
+ * @author Kevin Roast
+ */
+public class ApproveDocEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = 2958297435415449179L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ Map properties = node.getProperties();
+
+ Boolean approveMove = (Boolean) properties.get("app:approveMove");
+ boolean isMove = approveMove == null ? false : approveMove;
+
+ boolean canProceed = (properties.get("app:approveStep") != null) && !node.isLocked();
+ //If this approval is going to result in a move of the node then we check whether the user
+ //has permission. The delete permission is required in order to move a node (odd, perhaps, but true).
+ canProceed &= (!isMove || node.hasPermission(PermissionService.DELETE));
+
+ return canProceed;
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/CancelCheckoutDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/CancelCheckoutDocEvaluator.java
index d4fb452893..fc7636128c 100644
--- a/source/java/org/alfresco/web/action/evaluator/CancelCheckoutDocEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/CancelCheckoutDocEvaluator.java
@@ -1,25 +1,25 @@
-package org.alfresco.web.action.evaluator;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.web.bean.repository.Node;
-
-/**
- * UI Action Evaluator - Cancel checkout document.
- *
- * @author Kevin Roast
- */
-public class CancelCheckoutDocEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = -9015403093449070254L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- return (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) &&
- node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE) == null &&
- node.hasPermission(PermissionService.CANCEL_CHECK_OUT));
- }
+package org.alfresco.web.action.evaluator;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.web.bean.repository.Node;
+
+/**
+ * UI Action Evaluator - Cancel checkout document.
+ *
+ * @author Kevin Roast
+ */
+public class CancelCheckoutDocEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = -9015403093449070254L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ return (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) &&
+ node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE) == null &&
+ node.hasPermission(PermissionService.CANCEL_CHECK_OUT));
+ }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/web/action/evaluator/CancelWorkflowEvaluator.java b/source/java/org/alfresco/web/action/evaluator/CancelWorkflowEvaluator.java
index d1aba4f675..fb3bcace31 100644
--- a/source/java/org/alfresco/web/action/evaluator/CancelWorkflowEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/CancelWorkflowEvaluator.java
@@ -1,59 +1,59 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.workflow.WorkflowTask;
-import org.alfresco.web.app.Application;
-import org.alfresco.web.bean.repository.Node;
-import org.alfresco.web.bean.repository.Repository;
-import org.alfresco.web.bean.repository.User;
-
-/**
- * UI Action Evaluator for cancel workflow action. The action
- * is only allowed if the workflow the task belongs to was
- * started by the current user.
- *
- * @author gavinc
- */
-public class CancelWorkflowEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = 7663087149225546333L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- boolean result = false;
- FacesContext context = FacesContext.getCurrentInstance();
-
- // get the task from the node
- WorkflowTask task = (WorkflowTask)node.getProperties().get("workflowTask");
- if (task != null)
- {
- NodeRef initiator = task.path.instance.initiator;
- if (initiator != null)
- {
- // find the current username
- User user = Application.getCurrentUser(context);
- String currentUserName = user.getUserName();
-
- // get the username of the initiator
- NodeService nodeSvc = Repository.getServiceRegistry(
- context).getNodeService();
- String userName = (String)nodeSvc.getProperty(initiator, ContentModel.PROP_USERNAME);
-
- // if the current user started the workflow allow the cancel action
- if (currentUserName.equals(userName))
- {
- result = true;
- }
- }
- }
-
- return result;
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.workflow.WorkflowTask;
+import org.alfresco.web.app.Application;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.Repository;
+import org.alfresco.web.bean.repository.User;
+
+/**
+ * UI Action Evaluator for cancel workflow action. The action
+ * is only allowed if the workflow the task belongs to was
+ * started by the current user.
+ *
+ * @author gavinc
+ */
+public class CancelWorkflowEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = 7663087149225546333L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ boolean result = false;
+ FacesContext context = FacesContext.getCurrentInstance();
+
+ // get the task from the node
+ WorkflowTask task = (WorkflowTask)node.getProperties().get("workflowTask");
+ if (task != null)
+ {
+ NodeRef initiator = task.path.instance.initiator;
+ if (initiator != null)
+ {
+ // find the current username
+ User user = Application.getCurrentUser(context);
+ String currentUserName = user.getUserName();
+
+ // get the username of the initiator
+ NodeService nodeSvc = Repository.getServiceRegistry(
+ context).getNodeService();
+ String userName = (String)nodeSvc.getProperty(initiator, ContentModel.PROP_USERNAME);
+
+ // if the current user started the workflow allow the cancel action
+ if (currentUserName.equals(userName))
+ {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/CheckinDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/CheckinDocEvaluator.java
index 565c6f0852..8099a07e3a 100644
--- a/source/java/org/alfresco/web/action/evaluator/CheckinDocEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/CheckinDocEvaluator.java
@@ -1,25 +1,25 @@
-package org.alfresco.web.action.evaluator;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.web.bean.repository.Node;
-
-/**
- * UI Action Evaluator - Checkin document.
- *
- * @author Kevin Roast
- */
-public class CheckinDocEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = 5398249535631219663L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- return (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) &&
- node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE) == null &&
- node.hasPermission(PermissionService.CHECK_IN));
- }
+package org.alfresco.web.action.evaluator;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.web.bean.repository.Node;
+
+/**
+ * UI Action Evaluator - Checkin document.
+ *
+ * @author Kevin Roast
+ */
+public class CheckinDocEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = 5398249535631219663L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ return (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) &&
+ node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE) == null &&
+ node.hasPermission(PermissionService.CHECK_IN));
+ }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/web/action/evaluator/CheckoutDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/CheckoutDocEvaluator.java
index b624a4f6f0..282027b133 100644
--- a/source/java/org/alfresco/web/action/evaluator/CheckoutDocEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/CheckoutDocEvaluator.java
@@ -1,34 +1,34 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.dictionary.DictionaryService;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.web.bean.repository.Node;
-import org.alfresco.web.bean.repository.Repository;
-
-/**
- * UI Action Evaluator - Checkout document.
- *
- * @author Kevin Roast
- */
-public class CheckoutDocEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = 5510366635124591353L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- DictionaryService dd = Repository.getServiceRegistry(
- FacesContext.getCurrentInstance()).getDictionaryService();
-
- return dd.isSubClass(node.getType(), ContentModel.TYPE_CONTENT) &&
- ((node.hasPermission(PermissionService.CHECK_OUT) &&
- (node.isLocked() == false &&
- node.hasAspect(ContentModel.ASPECT_WORKING_COPY) == false) &&
- node.hasAspect(ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION) == false));
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.Repository;
+
+/**
+ * UI Action Evaluator - Checkout document.
+ *
+ * @author Kevin Roast
+ */
+public class CheckoutDocEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = 5510366635124591353L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ DictionaryService dd = Repository.getServiceRegistry(
+ FacesContext.getCurrentInstance()).getDictionaryService();
+
+ return dd.isSubClass(node.getType(), ContentModel.TYPE_CONTENT) &&
+ ((node.hasPermission(PermissionService.CHECK_OUT) &&
+ (node.isLocked() == false &&
+ node.hasAspect(ContentModel.ASPECT_WORKING_COPY) == false) &&
+ node.hasAspect(ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION) == false));
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/CreateForumNodeEvaluator.java b/source/java/org/alfresco/web/action/evaluator/CreateForumNodeEvaluator.java
index 2cfbe36258..e7073e490c 100644
--- a/source/java/org/alfresco/web/action/evaluator/CreateForumNodeEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/CreateForumNodeEvaluator.java
@@ -1,23 +1,23 @@
-package org.alfresco.web.action.evaluator;
-
-import org.alfresco.model.ForumModel;
-import org.alfresco.web.bean.repository.Node;
-
-/**
- * UI Action Evaluator - Create a forum around a node.
- *
- * @author Kevin Roast
- */
-public class CreateForumNodeEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = -5132048668011887505L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- return (node.hasAspect(ForumModel.ASPECT_DISCUSSABLE) == false &&
- node.isLocked() == false);
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import org.alfresco.model.ForumModel;
+import org.alfresco.web.bean.repository.Node;
+
+/**
+ * UI Action Evaluator - Create a forum around a node.
+ *
+ * @author Kevin Roast
+ */
+public class CreateForumNodeEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = -5132048668011887505L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ return (node.hasAspect(ForumModel.ASPECT_DISCUSSABLE) == false &&
+ node.isLocked() == false);
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/DeleteDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/DeleteDocEvaluator.java
index 14d7d8f262..8c63969675 100644
--- a/source/java/org/alfresco/web/action/evaluator/DeleteDocEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/DeleteDocEvaluator.java
@@ -1,59 +1,59 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.ml.MultilingualContentService;
-import org.alfresco.web.app.servlet.FacesHelper;
-import org.alfresco.web.bean.ml.MultilingualUtils;
-import org.alfresco.web.bean.repository.Node;
-
-/**
- * UI Action Evaluator - Delete document.
- *
- * @author Kevin Roast
- */
-public class DeleteDocEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = 5742287199692844685L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- FacesContext fc = FacesContext.getCurrentInstance();
-
- // the node to delete is a ml container, test if the user has enought right on each translation
- if(node.getType().equals(ContentModel.TYPE_MULTILINGUAL_CONTAINER))
- {
- return MultilingualUtils.canDeleteEachTranslation(node, fc);
- }
-
- boolean isPivot = false;
-
- // special case for multilingual documents
- if (node.getAspects().contains(ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
- {
- MultilingualContentService mlservice =
- (MultilingualContentService) FacesHelper.getManagedBean(fc, "MultilingualContentService");
-
- // if the translation is the last translation, user can delete it
- if (mlservice.getTranslations(node.getNodeRef()).size() == 1)
- {
- isPivot = false;
- }
- // Else if the node is the pivot language, user can't delete it
- else if (mlservice.getPivotTranslation(node.getNodeRef()).getId()
- .equalsIgnoreCase(node.getNodeRef().getId()))
- {
- isPivot = true;
- }
- // finally, the node is not the pivot translation, user can delete it
- }
-
- return (node.isLocked() == false &&
- node.hasAspect(ContentModel.ASPECT_WORKING_COPY) == false &&
- isPivot == false);
- }
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.ml.MultilingualContentService;
+import org.alfresco.web.app.servlet.FacesHelper;
+import org.alfresco.web.bean.ml.MultilingualUtils;
+import org.alfresco.web.bean.repository.Node;
+
+/**
+ * UI Action Evaluator - Delete document.
+ *
+ * @author Kevin Roast
+ */
+public class DeleteDocEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = 5742287199692844685L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ FacesContext fc = FacesContext.getCurrentInstance();
+
+ // the node to delete is a ml container, test if the user has enought right on each translation
+ if(node.getType().equals(ContentModel.TYPE_MULTILINGUAL_CONTAINER))
+ {
+ return MultilingualUtils.canDeleteEachTranslation(node, fc);
+ }
+
+ boolean isPivot = false;
+
+ // special case for multilingual documents
+ if (node.getAspects().contains(ContentModel.ASPECT_MULTILINGUAL_DOCUMENT))
+ {
+ MultilingualContentService mlservice =
+ (MultilingualContentService) FacesHelper.getManagedBean(fc, "MultilingualContentService");
+
+ // if the translation is the last translation, user can delete it
+ if (mlservice.getTranslations(node.getNodeRef()).size() == 1)
+ {
+ isPivot = false;
+ }
+ // Else if the node is the pivot language, user can't delete it
+ else if (mlservice.getPivotTranslation(node.getNodeRef()).getId()
+ .equalsIgnoreCase(node.getNodeRef().getId()))
+ {
+ isPivot = true;
+ }
+ // finally, the node is not the pivot translation, user can delete it
+ }
+
+ return (node.isLocked() == false &&
+ node.hasAspect(ContentModel.ASPECT_WORKING_COPY) == false &&
+ isPivot == false);
+ }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/web/action/evaluator/DiscussNodeEvaluator.java b/source/java/org/alfresco/web/action/evaluator/DiscussNodeEvaluator.java
index 10ef567b75..d241c796eb 100644
--- a/source/java/org/alfresco/web/action/evaluator/DiscussNodeEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/DiscussNodeEvaluator.java
@@ -1,47 +1,47 @@
-package org.alfresco.web.action.evaluator;
-
-import java.util.List;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ForumModel;
-import org.alfresco.service.cmr.repository.ChildAssociationRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.namespace.RegexQNamePattern;
-import org.alfresco.web.bean.repository.Node;
-import org.alfresco.web.bean.repository.Repository;
-
-/**
- * UI Action Evaluator - Discuss a node.
- *
- * @author Kevin Roast
- */
-public class DiscussNodeEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = 8754174908349998903L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- boolean result = false;
-
- if (node.hasAspect(ForumModel.ASPECT_DISCUSSABLE))
- {
- NodeService nodeService = Repository.getServiceRegistry(
- FacesContext.getCurrentInstance()).getNodeService();
- List children = nodeService.getChildAssocs(
- node.getNodeRef(), ForumModel.ASSOC_DISCUSSION,
- RegexQNamePattern.MATCH_ALL);
-
- // make sure there is one visible child association for the node
- if (children.size() == 1)
- {
- result = true;
- }
- }
-
- return result;
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import java.util.List;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ForumModel;
+import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.namespace.RegexQNamePattern;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.Repository;
+
+/**
+ * UI Action Evaluator - Discuss a node.
+ *
+ * @author Kevin Roast
+ */
+public class DiscussNodeEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = 8754174908349998903L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ boolean result = false;
+
+ if (node.hasAspect(ForumModel.ASPECT_DISCUSSABLE))
+ {
+ NodeService nodeService = Repository.getServiceRegistry(
+ FacesContext.getCurrentInstance()).getNodeService();
+ List children = nodeService.getChildAssocs(
+ node.getNodeRef(), ForumModel.ASSOC_DISCUSSION,
+ RegexQNamePattern.MATCH_ALL);
+
+ // make sure there is one visible child association for the node
+ if (children.size() == 1)
+ {
+ result = true;
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/DiscussionCopyEvaluator.java b/source/java/org/alfresco/web/action/evaluator/DiscussionCopyEvaluator.java
index 368f01f1cf..48c32fdfcd 100644
--- a/source/java/org/alfresco/web/action/evaluator/DiscussionCopyEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/DiscussionCopyEvaluator.java
@@ -1,59 +1,59 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.model.ForumModel;
-import org.alfresco.service.cmr.repository.ChildAssociationRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.service.namespace.QName;
-import org.alfresco.web.bean.repository.Node;
-import org.alfresco.web.bean.repository.Repository;
-
-/**
- * Evaluates whether the copy action should be visible.
- *
- * If the node is a discussion don't allow the action.
- *
- * @author gavinc
- */
-public class DiscussionCopyEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = -4080878553011296677L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- boolean result = true;
-
- // if the node in question is a forum...
- if (node.getType().equals(ForumModel.TYPE_FORUM))
- {
- // get the association type
- FacesContext context = FacesContext.getCurrentInstance();
- NodeService nodeService = Repository.getServiceRegistry(context).getNodeService();
-
- ChildAssociationRef parentAssoc = nodeService.getPrimaryParent(node.getNodeRef());
- QName assocType = parentAssoc.getTypeQName();
-
- // only allow the action if the association type is not the discussion assoc
- result = (assocType.equals(ForumModel.ASSOC_DISCUSSION) == false);
- }
-
- // impossible to copy a translation without content.
- if (result && node.getAspects().contains(ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
- {
- result = false;
- }
-
- if (!node.hasPermission(PermissionService.READ))
- {
- result = false;
- }
-
- return result;
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.model.ForumModel;
+import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.Repository;
+
+/**
+ * Evaluates whether the copy action should be visible.
+ *
+ * If the node is a discussion don't allow the action.
+ *
+ * @author gavinc
+ */
+public class DiscussionCopyEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = -4080878553011296677L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ boolean result = true;
+
+ // if the node in question is a forum...
+ if (node.getType().equals(ForumModel.TYPE_FORUM))
+ {
+ // get the association type
+ FacesContext context = FacesContext.getCurrentInstance();
+ NodeService nodeService = Repository.getServiceRegistry(context).getNodeService();
+
+ ChildAssociationRef parentAssoc = nodeService.getPrimaryParent(node.getNodeRef());
+ QName assocType = parentAssoc.getTypeQName();
+
+ // only allow the action if the association type is not the discussion assoc
+ result = (assocType.equals(ForumModel.ASSOC_DISCUSSION) == false);
+ }
+
+ // impossible to copy a translation without content.
+ if (result && node.getAspects().contains(ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
+ {
+ result = false;
+ }
+
+ if (!node.hasPermission(PermissionService.READ))
+ {
+ result = false;
+ }
+
+ return result;
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/DiscussionCutEvaluator.java b/source/java/org/alfresco/web/action/evaluator/DiscussionCutEvaluator.java
index c1ec34da15..6fe73b6fce 100644
--- a/source/java/org/alfresco/web/action/evaluator/DiscussionCutEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/DiscussionCutEvaluator.java
@@ -1,46 +1,46 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ForumModel;
-import org.alfresco.service.cmr.repository.ChildAssociationRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.namespace.QName;
-import org.alfresco.web.bean.repository.Node;
-import org.alfresco.web.bean.repository.Repository;
-
-/**
- * Evaluates whether the cut action should be visible.
- *
- * If the node is a discussion don't allow the action.
- *
- * @author gavinc
- */
-public class DiscussionCutEvaluator extends CutNodeEvaluator
-{
- private static final long serialVersionUID = 7260556874788184200L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- boolean result = super.evaluate(node);
-
- // if the node in question is a forum...
- if (result && node.getType().equals(ForumModel.TYPE_FORUM))
- {
- // get the association type
- FacesContext context = FacesContext.getCurrentInstance();
- NodeService nodeService = Repository.getServiceRegistry(context).getNodeService();
-
- ChildAssociationRef parentAssoc = nodeService.getPrimaryParent(node.getNodeRef());
- QName assocType = parentAssoc.getTypeQName();
-
- // only allow the action if the association type is not the discussion assoc
- result = (assocType.equals(ForumModel.ASSOC_DISCUSSION) == false);
- }
-
- return result;
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ForumModel;
+import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.Repository;
+
+/**
+ * Evaluates whether the cut action should be visible.
+ *
+ * If the node is a discussion don't allow the action.
+ *
+ * @author gavinc
+ */
+public class DiscussionCutEvaluator extends CutNodeEvaluator
+{
+ private static final long serialVersionUID = 7260556874788184200L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ boolean result = super.evaluate(node);
+
+ // if the node in question is a forum...
+ if (result && node.getType().equals(ForumModel.TYPE_FORUM))
+ {
+ // get the association type
+ FacesContext context = FacesContext.getCurrentInstance();
+ NodeService nodeService = Repository.getServiceRegistry(context).getNodeService();
+
+ ChildAssociationRef parentAssoc = nodeService.getPrimaryParent(node.getNodeRef());
+ QName assocType = parentAssoc.getTypeQName();
+
+ // only allow the action if the association type is not the discussion assoc
+ result = (assocType.equals(ForumModel.ASSOC_DISCUSSION) == false);
+ }
+
+ return result;
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/EditDocCIFSEvaluator.java b/source/java/org/alfresco/web/action/evaluator/EditDocCIFSEvaluator.java
index 1d5ac7a01f..5e2daa28c0 100644
--- a/source/java/org/alfresco/web/action/evaluator/EditDocCIFSEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/EditDocCIFSEvaluator.java
@@ -1,51 +1,51 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ApplicationModel;
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.dictionary.DictionaryService;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.web.app.Application;
-import org.alfresco.web.bean.coci.EditOnlineDialog;
-import org.alfresco.web.bean.repository.Node;
-import org.alfresco.web.bean.repository.Repository;
-
-/**
- * UI Action Evaluator - Edit document via CIFS.
- *
- * @author Kevin Roast
- */
-public class EditDocCIFSEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = -8988276140748731926L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- FacesContext fc = FacesContext.getCurrentInstance();
- DictionaryService dd = Repository.getServiceRegistry(fc).getDictionaryService();
-
- boolean result = false;
-
- // if the node is inline editable, the default http behaviour should always be used
- if (dd.isSubClass(node.getType(), ContentModel.TYPE_CONTENT))
- {
- if (node.hasAspect(ApplicationModel.ASPECT_INLINEEDITABLE) == false &&
- "cifs".equals(Application.getClientConfig(fc).getEditLinkType()))
- {
- if ((node.isWorkingCopyOwner() == true && node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE) != null &&
- node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE).equals(EditOnlineDialog.ONLINE_EDITING))||
- (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) && node.hasPermission(PermissionService.WRITE)) ||
- (node.isLocked() == false && node.hasAspect(ContentModel.ASPECT_WORKING_COPY) == false))
- {
- result = true;
- }
- }
- }
-
- return result;
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ApplicationModel;
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.web.app.Application;
+import org.alfresco.web.bean.coci.EditOnlineDialog;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.Repository;
+
+/**
+ * UI Action Evaluator - Edit document via CIFS.
+ *
+ * @author Kevin Roast
+ */
+public class EditDocCIFSEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = -8988276140748731926L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ FacesContext fc = FacesContext.getCurrentInstance();
+ DictionaryService dd = Repository.getServiceRegistry(fc).getDictionaryService();
+
+ boolean result = false;
+
+ // if the node is inline editable, the default http behaviour should always be used
+ if (dd.isSubClass(node.getType(), ContentModel.TYPE_CONTENT))
+ {
+ if (node.hasAspect(ApplicationModel.ASPECT_INLINEEDITABLE) == false &&
+ "cifs".equals(Application.getClientConfig(fc).getEditLinkType()))
+ {
+ if ((node.isWorkingCopyOwner() == true && node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE) != null &&
+ node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE).equals(EditOnlineDialog.ONLINE_EDITING))||
+ (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) && node.hasPermission(PermissionService.WRITE)) ||
+ (node.isLocked() == false && node.hasAspect(ContentModel.ASPECT_WORKING_COPY) == false))
+ {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/EditDocHttpEvaluator.java b/source/java/org/alfresco/web/action/evaluator/EditDocHttpEvaluator.java
index be1e7c5b2e..9c4d6f7f62 100644
--- a/source/java/org/alfresco/web/action/evaluator/EditDocHttpEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/EditDocHttpEvaluator.java
@@ -1,59 +1,59 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ApplicationModel;
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.dictionary.DictionaryService;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.web.app.Application;
-import org.alfresco.web.bean.coci.EditOnlineDialog;
-import org.alfresco.web.bean.repository.Node;
-import org.alfresco.web.bean.repository.Repository;
-
-/**
- * UI Action Evaluator - Edit document via HTTP or inline edit.
- *
- * @author Kevin Roast
- */
-public class EditDocHttpEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = -3694679925715830430L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- FacesContext fc = FacesContext.getCurrentInstance();
- DictionaryService dd = Repository.getServiceRegistry(fc).getDictionaryService();
-
- boolean result = false;
-
- // Since the reader returned of an empty translation is the reader of it's pivot translation, it makes
- // no sens to edit it on-line.
- if(node.getAspects().contains(ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
- {
- //result = false
- }
- // if the node is inline editable, the default http behaviour should
- // always be used otherwise the configured approach is used
- else if (dd.isSubClass(node.getType(), ContentModel.TYPE_CONTENT))
- {
- if (node.hasAspect(ApplicationModel.ASPECT_INLINEEDITABLE) == true &&
- node.getProperties().get(ApplicationModel.PROP_EDITINLINE) != null &&
- ((Boolean)node.getProperties().get(ApplicationModel.PROP_EDITINLINE)).booleanValue() == true)
- {
- if ((node.isWorkingCopyOwner() == true && node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE) != null &&
- node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE).equals(EditOnlineDialog.ONLINE_EDITING)) ||
- (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) && node.hasPermission(PermissionService.WRITE)) ||
- (node.isLocked() == false && node.hasAspect(ContentModel.ASPECT_WORKING_COPY) == false))
- {
- result = true;
- }
- }
- }
-
- return result;
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ApplicationModel;
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.web.app.Application;
+import org.alfresco.web.bean.coci.EditOnlineDialog;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.Repository;
+
+/**
+ * UI Action Evaluator - Edit document via HTTP or inline edit.
+ *
+ * @author Kevin Roast
+ */
+public class EditDocHttpEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = -3694679925715830430L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ FacesContext fc = FacesContext.getCurrentInstance();
+ DictionaryService dd = Repository.getServiceRegistry(fc).getDictionaryService();
+
+ boolean result = false;
+
+ // Since the reader returned of an empty translation is the reader of it's pivot translation, it makes
+ // no sens to edit it on-line.
+ if(node.getAspects().contains(ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION))
+ {
+ //result = false
+ }
+ // if the node is inline editable, the default http behaviour should
+ // always be used otherwise the configured approach is used
+ else if (dd.isSubClass(node.getType(), ContentModel.TYPE_CONTENT))
+ {
+ if (node.hasAspect(ApplicationModel.ASPECT_INLINEEDITABLE) == true &&
+ node.getProperties().get(ApplicationModel.PROP_EDITINLINE) != null &&
+ ((Boolean)node.getProperties().get(ApplicationModel.PROP_EDITINLINE)).booleanValue() == true)
+ {
+ if ((node.isWorkingCopyOwner() == true && node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE) != null &&
+ node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE).equals(EditOnlineDialog.ONLINE_EDITING)) ||
+ (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) && node.hasPermission(PermissionService.WRITE)) ||
+ (node.isLocked() == false && node.hasAspect(ContentModel.ASPECT_WORKING_COPY) == false))
+ {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/EditDocWebDavEvaluator.java b/source/java/org/alfresco/web/action/evaluator/EditDocWebDavEvaluator.java
index a36f0801c9..b18fef01a3 100644
--- a/source/java/org/alfresco/web/action/evaluator/EditDocWebDavEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/EditDocWebDavEvaluator.java
@@ -1,50 +1,50 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ApplicationModel;
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.dictionary.DictionaryService;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.web.app.Application;
-import org.alfresco.web.bean.coci.EditOnlineDialog;
-import org.alfresco.web.bean.repository.Node;
-import org.alfresco.web.bean.repository.Repository;
-
-/**
- * UI Action Evaluator - Edit document via Webdav.
- *
- * @author Kevin Roast
- */
-public class EditDocWebDavEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = 293342561997588700L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- FacesContext fc = FacesContext.getCurrentInstance();
- DictionaryService dd = Repository.getServiceRegistry(fc).getDictionaryService();
-
- boolean result = false;
-
- // if the node is inline editable, the default http behaviour should always be used
- if (dd.isSubClass(node.getType(), ContentModel.TYPE_CONTENT))
- {
- if (node.hasAspect(ApplicationModel.ASPECT_INLINEEDITABLE) == false &&
- "webdav".equals(Application.getClientConfig(fc).getEditLinkType()))
- {
- if ((node.isWorkingCopyOwner() == true && node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE).equals(EditOnlineDialog.ONLINE_EDITING)) ||
- (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) && node.hasPermission(PermissionService.WRITE)) ||
- (node.isLocked() == false && node.hasAspect(ContentModel.ASPECT_WORKING_COPY) == false))
- {
- result = true;
- }
- }
- }
-
- return result;
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ApplicationModel;
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.web.app.Application;
+import org.alfresco.web.bean.coci.EditOnlineDialog;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.Repository;
+
+/**
+ * UI Action Evaluator - Edit document via Webdav.
+ *
+ * @author Kevin Roast
+ */
+public class EditDocWebDavEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = 293342561997588700L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ FacesContext fc = FacesContext.getCurrentInstance();
+ DictionaryService dd = Repository.getServiceRegistry(fc).getDictionaryService();
+
+ boolean result = false;
+
+ // if the node is inline editable, the default http behaviour should always be used
+ if (dd.isSubClass(node.getType(), ContentModel.TYPE_CONTENT))
+ {
+ if (node.hasAspect(ApplicationModel.ASPECT_INLINEEDITABLE) == false &&
+ "webdav".equals(Application.getClientConfig(fc).getEditLinkType()))
+ {
+ if ((node.isWorkingCopyOwner() == true && node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE).equals(EditOnlineDialog.ONLINE_EDITING)) ||
+ (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) && node.hasPermission(PermissionService.WRITE)) ||
+ (node.isLocked() == false && node.hasAspect(ContentModel.ASPECT_WORKING_COPY) == false))
+ {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/ForumsCheckinDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/ForumsCheckinDocEvaluator.java
index db04da226b..13cad8c286 100644
--- a/source/java/org/alfresco/web/action/evaluator/ForumsCheckinDocEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/ForumsCheckinDocEvaluator.java
@@ -1,54 +1,54 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.model.ForumModel;
-import org.alfresco.service.cmr.coci.CheckOutCheckInService;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.web.bean.repository.Node;
-import org.alfresco.web.bean.repository.Repository;
-
-/**
- * UI Action Evaluator - Checkin a document with potentially a Forum attached.
- *
- * @author Kevin Roast
- */
-public class ForumsCheckinDocEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = -924897450989526336L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- boolean allow = false;
-
- if (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) &&
- node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE) == null)
- {
- if (node.hasAspect(ForumModel.ASPECT_DISCUSSABLE))
- {
- CheckOutCheckInService checkOutCheckInService =
- Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getCheckOutCheckInService();
- // get the original locked node (via the copiedfrom aspect)
- NodeRef lockedNodeRef = checkOutCheckInService.getCheckedOut(node.getNodeRef());
- if (lockedNodeRef != null)
- {
- Node lockedNode = new Node(lockedNodeRef);
- allow = (node.hasPermission(PermissionService.CHECK_IN) &&
- lockedNode.hasPermission(PermissionService.CONTRIBUTOR));
- }
- }
- else
- {
- // there is no discussion so just check they have checkin permission for the node
- allow = node.hasPermission(PermissionService.CHECK_IN);
- }
- }
-
- return allow;
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.model.ForumModel;
+import org.alfresco.service.cmr.coci.CheckOutCheckInService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.Repository;
+
+/**
+ * UI Action Evaluator - Checkin a document with potentially a Forum attached.
+ *
+ * @author Kevin Roast
+ */
+public class ForumsCheckinDocEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = -924897450989526336L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ boolean allow = false;
+
+ if (node.hasAspect(ContentModel.ASPECT_WORKING_COPY) &&
+ node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE) == null)
+ {
+ if (node.hasAspect(ForumModel.ASPECT_DISCUSSABLE))
+ {
+ CheckOutCheckInService checkOutCheckInService =
+ Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getCheckOutCheckInService();
+ // get the original locked node (via the copiedfrom aspect)
+ NodeRef lockedNodeRef = checkOutCheckInService.getCheckedOut(node.getNodeRef());
+ if (lockedNodeRef != null)
+ {
+ Node lockedNode = new Node(lockedNodeRef);
+ allow = (node.hasPermission(PermissionService.CHECK_IN) &&
+ lockedNode.hasPermission(PermissionService.CONTRIBUTOR));
+ }
+ }
+ else
+ {
+ // there is no discussion so just check they have checkin permission for the node
+ allow = node.hasPermission(PermissionService.CHECK_IN);
+ }
+ }
+
+ return allow;
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/RejectDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/RejectDocEvaluator.java
index 2e3f4f8a1a..965a1c4804 100644
--- a/source/java/org/alfresco/web/action/evaluator/RejectDocEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/RejectDocEvaluator.java
@@ -1,22 +1,22 @@
-package org.alfresco.web.action.evaluator;
-
-import org.alfresco.web.bean.repository.Node;
-
-/**
- * UI Action Evaluator - 'Reject' workflow step for document or space.
- *
- * @author Kevin Roast
- */
-public class RejectDocEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = -7733947744617999298L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- return (node.getProperties().get("app:rejectStep") != null &&
- node.isLocked() == false);
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import org.alfresco.web.bean.repository.Node;
+
+/**
+ * UI Action Evaluator - 'Reject' workflow step for document or space.
+ *
+ * @author Kevin Roast
+ */
+public class RejectDocEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = -7733947744617999298L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ return (node.getProperties().get("app:rejectStep") != null &&
+ node.isLocked() == false);
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/ShortcutNodeEvaluator.java b/source/java/org/alfresco/web/action/evaluator/ShortcutNodeEvaluator.java
index 8cd8732b06..f2c8d4e491 100644
--- a/source/java/org/alfresco/web/action/evaluator/ShortcutNodeEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/ShortcutNodeEvaluator.java
@@ -1,27 +1,27 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.web.app.servlet.FacesHelper;
-import org.alfresco.web.bean.NavigationBean;
-import org.alfresco.web.bean.repository.Node;
-
-/**
- * UI Action Evaluator - Create a shortcut to a node.
- *
- * @author Kevin Roast
- */
-public class ShortcutNodeEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = 8768692540125721144L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- NavigationBean nav =
- (NavigationBean)FacesHelper.getManagedBean(FacesContext.getCurrentInstance(), NavigationBean.BEAN_NAME);
- return (nav.getIsGuest() == false);
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.web.app.servlet.FacesHelper;
+import org.alfresco.web.bean.NavigationBean;
+import org.alfresco.web.bean.repository.Node;
+
+/**
+ * UI Action Evaluator - Create a shortcut to a node.
+ *
+ * @author Kevin Roast
+ */
+public class ShortcutNodeEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = 8768692540125721144L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ NavigationBean nav =
+ (NavigationBean)FacesHelper.getManagedBean(FacesContext.getCurrentInstance(), NavigationBean.BEAN_NAME);
+ return (nav.getIsGuest() == false);
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/StartWorkflowEvaluator.java b/source/java/org/alfresco/web/action/evaluator/StartWorkflowEvaluator.java
index f24ee88a41..c68c266117 100644
--- a/source/java/org/alfresco/web/action/evaluator/StartWorkflowEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/StartWorkflowEvaluator.java
@@ -1,45 +1,45 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.repo.workflow.BPMEngineRegistry;
-import org.alfresco.web.app.servlet.FacesHelper;
-import org.alfresco.web.bean.NavigationBean;
-import org.alfresco.web.bean.repository.Node;
-import org.springframework.web.context.WebApplicationContext;
-import org.springframework.web.jsf.FacesContextUtils;
-
-/**
- * UI Action Evaluator - Start workflow on a node.
- *
- * @author gavinc
- */
-public class StartWorkflowEvaluator extends BaseActionEvaluator
-{
- private static final String BPM_ENGINE_BEAN_NAME = "bpm_engineRegistry";
- private static final long serialVersionUID = 3110333488835027710L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- FacesContext facesContext = FacesContext.getCurrentInstance();
- NavigationBean nav =
- (NavigationBean)FacesHelper.getManagedBean(facesContext, NavigationBean.BEAN_NAME);
-
- // determine whether the workflow services are active
- boolean workflowPresent = false;
- WebApplicationContext springContext = FacesContextUtils.getRequiredWebApplicationContext(facesContext);
- BPMEngineRegistry bpmReg = (BPMEngineRegistry)springContext.getBean(BPM_ENGINE_BEAN_NAME);
- if (bpmReg != null)
- {
- String[] components = bpmReg.getWorkflowComponents();
- workflowPresent = (components != null && components.length > 0);
- }
-
- return (workflowPresent && nav.getIsGuest() == false &&
- node.hasAspect(ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION) == false);
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.workflow.BPMEngineRegistry;
+import org.alfresco.web.app.servlet.FacesHelper;
+import org.alfresco.web.bean.NavigationBean;
+import org.alfresco.web.bean.repository.Node;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.jsf.FacesContextUtils;
+
+/**
+ * UI Action Evaluator - Start workflow on a node.
+ *
+ * @author gavinc
+ */
+public class StartWorkflowEvaluator extends BaseActionEvaluator
+{
+ private static final String BPM_ENGINE_BEAN_NAME = "bpm_engineRegistry";
+ private static final long serialVersionUID = 3110333488835027710L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ NavigationBean nav =
+ (NavigationBean)FacesHelper.getManagedBean(facesContext, NavigationBean.BEAN_NAME);
+
+ // determine whether the workflow services are active
+ boolean workflowPresent = false;
+ WebApplicationContext springContext = FacesContextUtils.getRequiredWebApplicationContext(facesContext);
+ BPMEngineRegistry bpmReg = (BPMEngineRegistry)springContext.getBean(BPM_ENGINE_BEAN_NAME);
+ if (bpmReg != null)
+ {
+ String[] components = bpmReg.getWorkflowComponents();
+ workflowPresent = (components != null && components.length > 0);
+ }
+
+ return (workflowPresent && nav.getIsGuest() == false &&
+ node.hasAspect(ContentModel.ASPECT_MULTILINGUAL_EMPTY_TRANSLATION) == false);
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/TakeOwnershipDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/TakeOwnershipDocEvaluator.java
index 4bb37c06de..c03a0e006e 100644
--- a/source/java/org/alfresco/web/action/evaluator/TakeOwnershipDocEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/TakeOwnershipDocEvaluator.java
@@ -1,21 +1,21 @@
-package org.alfresco.web.action.evaluator;
-
-import org.alfresco.web.bean.repository.Node;
-
-/**
- * UI Action Evaluator - Take ownership of a document.
- *
- * @author Kevin Roast
- */
-public class TakeOwnershipDocEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = 3966463533922521230L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- return (node.isLocked() == false);
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import org.alfresco.web.bean.repository.Node;
+
+/**
+ * UI Action Evaluator - Take ownership of a document.
+ *
+ * @author Kevin Roast
+ */
+public class TakeOwnershipDocEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = 3966463533922521230L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ return (node.isLocked() == false);
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/UnlockDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/UnlockDocEvaluator.java
index 5ce15b3e4c..7de2279d8c 100644
--- a/source/java/org/alfresco/web/action/evaluator/UnlockDocEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/UnlockDocEvaluator.java
@@ -1,35 +1,35 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.service.cmr.coci.CheckOutCheckInService;
-import org.alfresco.web.app.servlet.FacesHelper;
-import org.alfresco.web.bean.repository.Node;
-
-/**
- * UI Action Evaluator - Unlock a locked document.
- *
- * @author Kevin Roast
- */
-public class UnlockDocEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = -7056759932698306087L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- if (node.isLocked())
- {
- FacesContext fc = FacesContext.getCurrentInstance();
- CheckOutCheckInService checkOutCheckInService = (CheckOutCheckInService) FacesHelper.getManagedBean(fc, "CheckoutCheckinService");
- if (checkOutCheckInService.getWorkingCopy(node.getNodeRef()) == null)
- {
- return true;
- }
- }
-
- return false;
- }
-}
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.service.cmr.coci.CheckOutCheckInService;
+import org.alfresco.web.app.servlet.FacesHelper;
+import org.alfresco.web.bean.repository.Node;
+
+/**
+ * UI Action Evaluator - Unlock a locked document.
+ *
+ * @author Kevin Roast
+ */
+public class UnlockDocEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = -7056759932698306087L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ if (node.isLocked())
+ {
+ FacesContext fc = FacesContext.getCurrentInstance();
+ CheckOutCheckInService checkOutCheckInService = (CheckOutCheckInService) FacesHelper.getManagedBean(fc, "CheckoutCheckinService");
+ if (checkOutCheckInService.getWorkingCopy(node.getNodeRef()) == null)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/source/java/org/alfresco/web/action/evaluator/UnlockedDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/UnlockedDocEvaluator.java
index 00bbbd6c1b..1812a02b46 100644
--- a/source/java/org/alfresco/web/action/evaluator/UnlockedDocEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/UnlockedDocEvaluator.java
@@ -1,21 +1,21 @@
-package org.alfresco.web.action.evaluator;
-
-import org.alfresco.web.bean.repository.Node;
-
-/**
- * UI Action Evaluator - Proceed if the document is not locked.
- *
- * @author Kevin Roast
- */
-public class UnlockedDocEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = -3216759932698306123L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- return (node.isLocked() == false);
- }
+package org.alfresco.web.action.evaluator;
+
+import org.alfresco.web.bean.repository.Node;
+
+/**
+ * UI Action Evaluator - Proceed if the document is not locked.
+ *
+ * @author Kevin Roast
+ */
+public class UnlockedDocEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = -3216759932698306123L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ return (node.isLocked() == false);
+ }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/web/action/evaluator/UpdateDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/UpdateDocEvaluator.java
index 3313eb6cd6..07f781fec3 100644
--- a/source/java/org/alfresco/web/action/evaluator/UpdateDocEvaluator.java
+++ b/source/java/org/alfresco/web/action/evaluator/UpdateDocEvaluator.java
@@ -1,35 +1,35 @@
-package org.alfresco.web.action.evaluator;
-
-import javax.faces.context.FacesContext;
-
-import org.alfresco.model.ContentModel;
-import org.alfresco.service.cmr.dictionary.DictionaryService;
-import org.alfresco.web.bean.coci.EditOfflineDialog;
-import org.alfresco.web.bean.repository.Node;
-import org.alfresco.web.bean.repository.Repository;
-
-/**
- * UI Action Evaluator - Update document content.
- *
- * @author Kevin Roast
- */
-public class UpdateDocEvaluator extends BaseActionEvaluator
-{
- private static final long serialVersionUID = 6030963610213633893L;
-
- /**
- * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
- */
- public boolean evaluate(Node node)
- {
- DictionaryService dd = Repository.getServiceRegistry(
- FacesContext.getCurrentInstance()).getDictionaryService();
-
- boolean isOfflineEditing =
- (EditOfflineDialog.OFFLINE_EDITING.equals(node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE)));
-
- return dd.isSubClass(node.getType(), ContentModel.TYPE_CONTENT) &&
- ((node.isWorkingCopyOwner() && !isOfflineEditing) ||
- (!node.isLocked() && !node.hasAspect(ContentModel.ASPECT_WORKING_COPY)));
- }
+package org.alfresco.web.action.evaluator;
+
+import javax.faces.context.FacesContext;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.web.bean.coci.EditOfflineDialog;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.repository.Repository;
+
+/**
+ * UI Action Evaluator - Update document content.
+ *
+ * @author Kevin Roast
+ */
+public class UpdateDocEvaluator extends BaseActionEvaluator
+{
+ private static final long serialVersionUID = 6030963610213633893L;
+
+ /**
+ * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node)
+ */
+ public boolean evaluate(Node node)
+ {
+ DictionaryService dd = Repository.getServiceRegistry(
+ FacesContext.getCurrentInstance()).getDictionaryService();
+
+ boolean isOfflineEditing =
+ (EditOfflineDialog.OFFLINE_EDITING.equals(node.getProperties().get(ContentModel.PROP_WORKING_COPY_MODE)));
+
+ return dd.isSubClass(node.getType(), ContentModel.TYPE_CONTENT) &&
+ ((node.isWorkingCopyOwner() && !isOfflineEditing) ||
+ (!node.isLocked() && !node.hasAspect(ContentModel.ASPECT_WORKING_COPY)));
+ }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/web/app/AlfrescoNavigationHandler.java b/source/java/org/alfresco/web/app/AlfrescoNavigationHandler.java
index 40b308df20..d78842dbe3 100644
--- a/source/java/org/alfresco/web/app/AlfrescoNavigationHandler.java
+++ b/source/java/org/alfresco/web/app/AlfrescoNavigationHandler.java
@@ -1,977 +1,977 @@
-package org.alfresco.web.app;
-
-import java.util.Stack;
-
-import javax.faces.application.NavigationHandler;
-import javax.faces.application.ViewHandler;
-import javax.faces.component.UIViewRoot;
-import javax.faces.context.FacesContext;
-
-import org.springframework.extensions.config.Config;
-import org.springframework.extensions.config.ConfigService;
-import org.alfresco.service.cmr.repository.InvalidNodeRefException;
-import org.alfresco.web.app.servlet.FacesHelper;
-import org.alfresco.web.bean.NavigationBean;
-import org.alfresco.web.bean.dialog.DialogManager;
-import org.alfresco.web.bean.dialog.DialogState;
-import org.alfresco.web.bean.repository.Node;
-import org.alfresco.web.bean.wizard.WizardManager;
-import org.alfresco.web.bean.wizard.WizardState;
-import org.alfresco.web.config.DialogsConfigElement;
-import org.alfresco.web.config.NavigationConfigElement;
-import org.alfresco.web.config.NavigationElementReader;
-import org.alfresco.web.config.NavigationResult;
-import org.alfresco.web.config.WizardsConfigElement;
-import org.alfresco.web.config.DialogsConfigElement.DialogConfig;
-import org.alfresco.web.config.WizardsConfigElement.WizardConfig;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * @author gavinc
- */
-public class AlfrescoNavigationHandler extends NavigationHandler
-{
- public final static String OUTCOME_SEPARATOR = ":";
- public final static String OUTCOME_BROWSE = "browse";
- public final static String DIALOG_PREFIX = "dialog" + OUTCOME_SEPARATOR;
- public final static String WIZARD_PREFIX = "wizard" + OUTCOME_SEPARATOR;
- public final static String CLOSE_DIALOG_OUTCOME = DIALOG_PREFIX + "close";
- public final static String CLOSE_WIZARD_OUTCOME = WIZARD_PREFIX + "close";
- public final static String CLOSE_MULTIPLE_START = "[";
- public final static String CLOSE_MULTIPLE_END = "]";
- public final static String EXTERNAL_CONTAINER_SESSION = "externalDialogContainer";
-
- protected String dialogContainer = null;
- protected String wizardContainer = null;
- protected String plainDialogContainer = null;
- protected String plainWizardContainer = null;
-
- private final static Log logger = LogFactory.getLog(AlfrescoNavigationHandler.class);
- private final static String VIEW_STACK = "_alfViewStack";
-
- // The original navigation handler
- private NavigationHandler origHandler;
-
- /**
- * Default constructor
- *
- * @param origHandler The original navigation handler
- */
- public AlfrescoNavigationHandler(NavigationHandler origHandler)
- {
- super();
- this.origHandler = origHandler;
- }
-
- /**
- * @see javax.faces.application.NavigationHandler#handleNavigation(javax.faces.context.FacesContext, java.lang.String, java.lang.String)
- */
- @Override
- @SuppressWarnings("unchecked")
- public void handleNavigation(FacesContext context, String fromAction, String outcome)
- {
- if (logger.isDebugEnabled())
- {
- logger.debug("handleNavigation (fromAction=" + fromAction + ", outcome=" + outcome + ")");
- logger.debug("Current view id: " + context.getViewRoot().getViewId());
- }
-
- boolean isDialog = isDialog(outcome);
- if (isDialog || isWizard(outcome))
- {
- boolean dialogWizardClosing = isDialogOrWizardClosing(outcome);
- outcome = stripPrefix(outcome);
-
- if (dialogWizardClosing)
- {
- handleDialogOrWizardClose(context, fromAction, outcome, isDialog);
- }
- else
- {
- if (isDialog)
- {
- handleDialogOpen(context, fromAction, outcome);
- }
- else
- {
- handleWizardOpen(context, fromAction, outcome);
- }
- }
- }
- else
- {
- if (isWizardStep(fromAction))
- {
- goToView(context, getWizardContainer(context));
- }
- else
- {
- handleDispatch(context, fromAction, outcome);
- }
- }
-
- // reset the dispatch context
- Object bean = FacesHelper.getManagedBean(context, NavigationBean.BEAN_NAME);
- if (bean instanceof NavigationBean)
- {
- ((NavigationBean)bean).resetDispatchContext();
- }
-
- if (logger.isDebugEnabled())
- logger.debug("view stack: " + getViewStack(context));
- }
-
- /**
- * Determines whether the given outcome is dialog related
- *
- * @param outcome The outcome to test
- * @return true if outcome is dialog related i.e. starts with dialog:
- */
- protected boolean isDialog(String outcome)
- {
- boolean dialog = false;
-
- if (outcome != null && outcome.startsWith(DIALOG_PREFIX))
- {
- dialog = true;
- }
-
- return dialog;
- }
-
- /**
- * Determines whether the given outcome is wizard related
- *
- * @param outcome The outcome to test
- * @return true if outcome is wizard related
- * i.e. starts with create-wizard: or edit-wizard:
- */
- protected boolean isWizard(String outcome)
- {
- boolean wizard = false;
-
- if (outcome != null && outcome.startsWith(WIZARD_PREFIX))
- {
- wizard = true;
- }
-
- return wizard;
- }
-
- /**
- * Determines whether the given outcome represents a dialog or wizard closing
- *
- * @param outcome The outcome to test
- * @return true if the outcome represents a closing dialog or wizard
- */
- protected boolean isDialogOrWizardClosing(String outcome)
- {
- boolean closing = false;
-
- if (outcome != null &&
- (outcome.startsWith(CLOSE_DIALOG_OUTCOME) ||
- outcome.startsWith(CLOSE_WIZARD_OUTCOME)))
- {
- closing = true;
- }
-
- return closing;
- }
-
- protected int getNumberToClose(String outcome)
- {
- int toClose = 1;
-
- int idxStart = outcome.indexOf(CLOSE_MULTIPLE_START);
- if (outcome != null && idxStart != -1)
- {
- int idxEnd = outcome.indexOf(CLOSE_MULTIPLE_END);
- if (idxEnd != -1)
- {
- String closeNum = outcome.substring(idxStart+1, idxEnd);
- try
- {
- toClose = Integer.parseInt(closeNum);
- }
- catch (NumberFormatException nfe)
- {
- if (logger.isWarnEnabled())
- logger.warn("Could not determine number of containers to close, defaulting to 1");
- }
- }
-
- if (logger.isDebugEnabled())
- logger.debug("Closing " + toClose + " levels of container");
- }
-
- return toClose;
- }
-
- /**
- * Determines whether the given fromAction represents a step in the wizard
- * i.e. next or back
- *
- * @param fromAction The fromAction
- * @return true if the from action represents a wizard step
- */
- protected boolean isWizardStep(String fromAction)
- {
- boolean wizardStep = false;
-
- if (fromAction != null &&
- (fromAction.equals("#{WizardManager.next}") || fromAction.equals("#{WizardManager.back}")))
- {
- wizardStep = true;
- }
-
- return wizardStep;
- }
-
- /**
- * Removes the dialog or wizard prefix from the given outcome
- *
- * @param outcome The outcome to remove the prefix from
- * @return The remaining outcome
- */
- protected String stripPrefix(String outcome)
- {
- String newOutcome = outcome;
-
- if (outcome != null)
- {
- int idx = outcome.indexOf(OUTCOME_SEPARATOR);
- if (idx != -1)
- {
- newOutcome = outcome.substring(idx+1);
- }
- }
-
- return newOutcome;
- }
-
- /**
- * Returns the overridden outcome.
- * Used by dialogs and wizards to go to a particular page after it closes
- * rather than back to the page it was launched from.
- *
- * @param outcome The current outcome
- * @return The overridden outcome or null if there isn't an override
- */
- protected String getOutcomeOverride(String outcome)
- {
- String override = null;
-
- if (outcome != null)
- {
- int idx = outcome.indexOf(OUTCOME_SEPARATOR);
- if (idx != -1)
- {
- override = outcome.substring(idx+1);
- }
- }
-
- return override;
- }
-
- /**
- * Returns the dialog configuration object for the given dialog name.
- * If there is a node in the dispatch context a lookup is performed using
- * the node otherwise the global config section is used.
- *
- *
- * @param name The name of dialog being launched
- * @param dispatchContext The node being acted upon
- * @return The DialogConfig for the dialog or null if no config could be found
- */
- protected DialogConfig getDialogConfig(FacesContext context, String name, Node dispatchContext)
- {
- DialogConfig dialogConfig = null;
- ConfigService configSvc = Application.getConfigService(context);
-
- Config config = null;
-
- if (dispatchContext != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("Using dispatch context for dialog lookup: " +
- dispatchContext.getType().toString());
-
- // use the node to perform the lookup (this will include the global section)
- config = configSvc.getConfig(dispatchContext);
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("Looking up dialog in global config");
-
- // just use the global
- config = configSvc.getGlobalConfig();
- }
-
- if (config != null)
- {
- DialogsConfigElement dialogsCfg = (DialogsConfigElement)config.getConfigElement(
- DialogsConfigElement.CONFIG_ELEMENT_ID);
- if (dialogsCfg != null)
- {
- dialogConfig = dialogsCfg.getDialog(name);
- }
- }
-
- return dialogConfig;
- }
-
- /**
- * Returns the wizard configuration object for the given wizard name.
- * If there is a node in the dispatch context a lookup is performed using
- * the node otherwise the global config section is used.
- *
- * @param name The name of wizard being launched
- * @param dispatchContext The node being acted upon
- * @return The WizardConfig for the wizard or null if no config could be found
- */
- protected WizardConfig getWizardConfig(FacesContext context, String name, Node dispatchContext)
- {
- WizardConfig wizardConfig = null;
- ConfigService configSvc = Application.getConfigService(context);
-
- Config config = null;
-
- if (dispatchContext != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("Using dispatch context for wizard lookup: " +
- dispatchContext.getType().toString());
-
- // use the node to perform the lookup (this will include the global section)
- config = configSvc.getConfig(dispatchContext);
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("Looking up wizard in global config");
-
- // just use the global
- config = configSvc.getGlobalConfig();
- }
-
- if (config != null)
- {
- WizardsConfigElement wizardsCfg = (WizardsConfigElement)config.getConfigElement(
- WizardsConfigElement.CONFIG_ELEMENT_ID);
- if (wizardsCfg != null)
- {
- wizardConfig = wizardsCfg.getWizard(name);
- }
- }
-
- return wizardConfig;
- }
-
- /**
- * Retrieves the configured dialog container page
- *
- * @param context FacesContext
- * @return The container page
- */
- protected String getDialogContainer(FacesContext context)
- {
- String container;
-
- // determine which kind of container we need to return, if the
- // external session flag is set then use the plain container
- Object obj = context.getExternalContext().getSessionMap().get(EXTERNAL_CONTAINER_SESSION);
-
- if (obj != null && obj instanceof Boolean && ((Boolean)obj).booleanValue())
- {
- if ((this.plainDialogContainer == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
- {
- ConfigService configSvc = Application.getConfigService(context);
- Config globalConfig = configSvc.getGlobalConfig();
-
- if (globalConfig != null)
- {
- this.plainDialogContainer = globalConfig.getConfigElement("plain-dialog-container").getValue();
- }
- }
-
- container = this.plainDialogContainer;
- }
- else
- {
- if ((this.dialogContainer == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
- {
- ConfigService configSvc = Application.getConfigService(context);
- Config globalConfig = configSvc.getGlobalConfig();
-
- if (globalConfig != null)
- {
- this.dialogContainer = globalConfig.getConfigElement("dialog-container").getValue();
- }
- }
-
- container = this.dialogContainer;
- }
-
- if (logger.isDebugEnabled())
- logger.debug("Using dialog container: " + container);
-
- return container;
- }
-
- /**
- * Retrieves the configured wizard container page
- *
- * @param context FacesContext
- * @return The container page
- */
- protected String getWizardContainer(FacesContext context)
- {
- String container;
-
- // determine which kind of container we need to return, if the
- // external session flag is set then use the plain container
- Object obj = context.getExternalContext().getSessionMap().get(EXTERNAL_CONTAINER_SESSION);
-
- if (obj != null && obj instanceof Boolean && ((Boolean)obj).booleanValue())
- {
- if ((this.plainWizardContainer == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
- {
- ConfigService configSvc = Application.getConfigService(context);
- Config globalConfig = configSvc.getGlobalConfig();
-
- if (globalConfig != null)
- {
- this.plainWizardContainer = globalConfig.getConfigElement("plain-wizard-container").getValue();
- }
- }
-
- container = this.plainWizardContainer;
- }
- else
- {
- if ((this.wizardContainer == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
- {
- ConfigService configSvc = Application.getConfigService(context);
- Config globalConfig = configSvc.getGlobalConfig();
-
- if (globalConfig != null)
- {
- this.wizardContainer = globalConfig.getConfigElement("wizard-container").getValue();
- }
- }
-
- container = this.wizardContainer;
- }
-
- if (logger.isDebugEnabled())
- logger.debug("Using wizard container: " + container);
-
- return container;
- }
-
- /**
- * Returns the node currently in the dispatch context
- *
- * @return The node currently in the dispatch context or null if
- * the dispatch context is empty
- */
- protected Node getDispatchContextNode(FacesContext context)
- {
- Node dispatchNode = null;
-
- NavigationBean navBean = (NavigationBean)context.getExternalContext().
- getSessionMap().get(NavigationBean.BEAN_NAME);
-
- if (navBean != null)
- {
- dispatchNode = navBean.getDispatchContextNode();
- }
-
- return dispatchNode;
- }
-
- protected void handleBrowseDispatch(FacesContext context, String fromAction, String outcome)
- {
- Node dispatchNode = null;
-
- NavigationBean navBean = (NavigationBean) context.getExternalContext().getSessionMap()
- .get(NavigationBean.BEAN_NAME);
-
- if (navBean != null)
- {
- dispatchNode = navBean.getCurrentNode();
- }
-
- handleDispatch(context, fromAction, outcome, dispatchNode);
- }
-
- /**
- * Processes any dispatching that may need to occur
- *
- * @param context Faces context
- * @param fromAction The from action
- * @param outcome The outcome
- */
- protected void handleDispatch(FacesContext context, String fromAction, String outcome)
- {
- Node dispatchNode = getDispatchContextNode(context);
- handleDispatch(context, fromAction, outcome, dispatchNode);
- }
-
- private void handleDispatch(FacesContext context, String fromAction, String outcome, Node dispatchNode)
- {
- if (dispatchNode != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("Found node with type '" + dispatchNode.getType().toString() +
- "' in dispatch context");
-
- // get the current view id
- String viewId = context.getViewRoot().getViewId();
-
- // see if there is any navigation config for the node type
- ConfigService configSvc = Application.getConfigService(context);
- NavigationConfigElement navigationCfg = null;
- try
- {
- Config nodeConfig = configSvc.getConfig(dispatchNode);
- navigationCfg = (NavigationConfigElement)nodeConfig.
- getConfigElement(NavigationElementReader.ELEMENT_NAVIGATION);
- }
- catch (InvalidNodeRefException e)
- {
- if (logger.isDebugEnabled()) logger.debug("Invalid node reference: " + dispatchNode);
- }
-
- if (navigationCfg != null)
- {
- // see if there is config for the current view state
- NavigationResult navResult = navigationCfg.getOverride(viewId, outcome);
-
- if (navResult != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("Found navigation config: " + navResult);
-
- if (navResult.isOutcome())
- {
- navigate(context, fromAction, navResult.getResult());
- }
- else
- {
- String newViewId = navResult.getResult();
-
- if (newViewId.equals(viewId) == false)
- {
- if (logger.isDebugEnabled())
- logger.debug("Dispatching to new view id: " + newViewId);
-
- goToView(context, newViewId);
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("New view id is the same as the current one so setting outcome to null");
-
- navigate(context, fromAction, null);
- }
- }
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("No override configuration found for current view or outcome");
-
- navigate(context, fromAction, outcome);
- }
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("No navigation configuration found for node");
-
- navigate(context, fromAction, outcome);
- }
-
- // reset the dispatch context
- ((NavigationBean)context.getExternalContext().getSessionMap().
- get(NavigationBean.BEAN_NAME)).resetDispatchContext();
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("No dispatch context found");
-
- // pass off to the original handler
- navigate(context, fromAction, outcome);
- }
- }
-
- /**
- * Opens a dialog
- *
- * @param context FacesContext
- * @param fromAction The fromAction
- * @param name The name of the dialog to open
- */
- protected void handleDialogOpen(FacesContext context, String fromAction, String name)
- {
- if (logger.isDebugEnabled())
- logger.debug("Opening dialog '" + name + "'");
-
- // firstly add the current view to the stack so we know where to go back to
- addCurrentViewToStack(context);
-
- DialogConfig config = getDialogConfig(context, name, getDispatchContextNode(context));
- if (config != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("Found config for dialog '" + name + "': " + config);
-
- // set the dialog manager up with the retrieved config
- DialogManager dialogManager = Application.getDialogManager();
- dialogManager.setCurrentDialog(config);
-
- // retrieve the container page and navigate to it
- goToView(context, getDialogContainer(context));
- }
- else
- {
- //logger.warn("Failed to find configuration for dialog '" + name + "'");
-
- // send the dialog name as the outcome to the original handler
- handleDispatch(context, fromAction, name);
- }
- }
-
- /**
- * Opens a wizard
- *
- * @param context FacesContext
- * @param fromAction The fromAction
- * @param name The name of the wizard to open
- */
- protected void handleWizardOpen(FacesContext context, String fromAction, String name)
- {
- if (logger.isDebugEnabled())
- logger.debug("Opening wizard '" + name + "'");
-
- // firstly add the current view to the stack so we know where to go back to
- addCurrentViewToStack(context);
-
- WizardConfig wizard = getWizardConfig(context, name, getDispatchContextNode(context));
- if (wizard != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("Found config for wizard '" + name + "': " + wizard);
-
- // set the wizard manager up with the retrieved config
- WizardManager wizardManager = Application.getWizardManager();
- wizardManager.setCurrentWizard(wizard);
-
- // retrieve the container page and navigate to it
- goToView(context, getWizardContainer(context));
- }
- else
- {
- //logger.warn("Failed to find configuration for wizard '" + name + "'");
-
- // send the dialog name as the outcome to the original handler
- handleDispatch(context, fromAction, name);
- }
- }
-
- /**
- * Closes the current dialog or wizard
- *
- * @param context FacesContext
- * @param fromAction The fromAction
- * @param outcome The outcome
- * @param dialog true if a dialog is being closed, false if a wizard is being closed
- */
- protected void handleDialogOrWizardClose(FacesContext context, String fromAction, String outcome, boolean dialog)
- {
- String closingItem = dialog ? "dialog" : "wizard";
-
- // if we are closing a wizard or dialog take the view off the
- // top of the stack then decide whether to use the view
- // or any overridden outcome that may be present
- if (getViewStack(context).empty() == false)
- {
- // is there an overidden outcome?
- String overriddenOutcome = getOutcomeOverride(outcome);
- if (overriddenOutcome == null)
- {
- // there isn't an overidden outcome so go back to the previous view
- if (logger.isDebugEnabled())
- logger.debug("Closing " + closingItem);
-
- // determine how many levels of dialog we need to close
- int numberToClose = getNumberToClose(outcome);
-
- Object stackObject = null;
- if (numberToClose == 1)
- {
- // just closing one dialog so get the item from the top of the stack
- stackObject = getViewStack(context).pop();
-
- if (logger.isDebugEnabled())
- logger.debug("Popped item from the top of the view stack: " + stackObject);
- }
- else
- {
- // check there are enough items on the stack, if there
- // isn't just get the last one (effectively going back
- // to the beginning)
- Stack viewStack = getViewStack(context);
- int itemsOnStack = viewStack.size();
- if (itemsOnStack < numberToClose)
- {
- if (logger.isDebugEnabled())
- logger.debug("Returning to first item on the view stack as there aren't " +
- numberToClose + " containers to close!");
-
- numberToClose = itemsOnStack;
- }
-
- // pop the right object from the stack
- for (int x = 1; x <= numberToClose; x++)
- {
- stackObject = viewStack.pop();
- }
-
- if (logger.isDebugEnabled())
- logger.debug("Popped item from the stack: " + stackObject);
- }
-
- // get the appropriate view id for the stack object
- String newViewId = getViewIdFromStackObject(context, stackObject);
-
- // go to the appropraite page
- goToView(context, newViewId);
- }
- else
- {
- // we also need to empty the dialog stack if we have been given
- // an overidden outcome as we could be going anywhere in the app.
- // grab the current top item first though in case we need to open
- // another dialog or wizard
- if (OUTCOME_BROWSE.equals(overriddenOutcome) == false)
- {
- String previousViewId = getViewIdFromStackObject(context, getViewStack(context).peek());
- getViewStack(context).clear();
-
- if (logger.isDebugEnabled())
- logger.debug("Closing " + closingItem + " with an overridden outcome of '" + overriddenOutcome + "'");
-
- // if the override is calling another dialog or wizard come back through
- // the navigation handler from the beginning
- if (isDialog(overriddenOutcome) || isWizard(overriddenOutcome))
- {
- // set the view id to the page at the top of the stack so when
- // the new dialog or wizard closes it goes back to the correct page
- context.getViewRoot().setViewId(previousViewId);
-
- if (logger.isDebugEnabled())
- {
- logger.debug("view stack: " + getViewStack(context));
- logger.debug("Opening '" + overriddenOutcome + "' after " + closingItem +
- " close using view id: " + previousViewId);
- }
-
- this.handleNavigation(context, fromAction, overriddenOutcome);
- }
- else
- {
- navigate(context, fromAction, overriddenOutcome);
- }
- }
- else
- {
- handleBrowseDispatch(context, fromAction, overriddenOutcome);
-
- // ALF-6661, always clear the view stack with an overridden outcome
- getViewStack(context).clear();
- }
- }
- }
- else
- {
- // we are trying to close a dialog when one hasn't been opened!
- // return to the main page of the app (print warning if debug is enabled)
- if (logger.isDebugEnabled())
- {
- logger.debug("Attempting to close a " + closingItem + " with an empty view stack, returning 'browse' outcome");
- }
-
- navigate(context, fromAction, OUTCOME_BROWSE);
- }
- }
-
- /**
- * Returns the view id of the given item retrieved from the view stack.
- *
- * @param context FacesContext
- * @param topOfStack The object retrieved from the view stack
- * @return The view id
- */
- protected String getViewIdFromStackObject(FacesContext context, Object topOfStack)
- {
- String viewId = null;
-
- // if the top of the stack is not a dialog or wizard just get the
- // view id and navigate back to it.
-
- // if the top of the stack is a dialog or wizard retrieve the state
- // and setup the appropriate manager with that state, then get the
- // appropriate container page and navigate to it.
-
- if (topOfStack instanceof String)
- {
- viewId = (String)topOfStack;
- }
- else if (topOfStack instanceof DialogState)
- {
- // restore the dialog state and get the dialog container viewId
- Application.getDialogManager().restoreState((DialogState)topOfStack);
- viewId = getDialogContainer(context);
- }
- else if (topOfStack instanceof WizardState)
- {
- // restore the wizard state and get the wizard container viewId
- Application.getWizardManager().restoreState((WizardState)topOfStack);
- viewId = getWizardContainer(context);
- }
- else
- {
- if (logger.isWarnEnabled())
- logger.warn("Invalid object found on view stack: " + topOfStack);
- }
-
- return viewId;
- }
-
- /**
- * Adds the current view to the stack (if required).
- * If the current view is already the top of the stack it is not added again
- * to stop the stack from growing and growing.
- *
- * @param context FacesContext
- */
- @SuppressWarnings("unchecked")
- protected void addCurrentViewToStack(FacesContext context)
- {
- // if the current viewId is either the dialog or wizard container page
- // we need to save the state of the current dialog or wizard to the stack
-
- // If the current view is a normal page and it is not the same as the
- // view currently at the top of the stack (you can't launch a dialog from
- // the same page 2 times in a row so it must mean the user navigated away
- // from the first dialog) just add the viewId to the stack
-
- // work out what to add to the stack
- String viewId = context.getViewRoot().getViewId();
- String dialogContainer = getDialogContainer(context);
- String wizardContainer = getWizardContainer(context);
- Object objectForStack = null;
- if (viewId.equals(dialogContainer))
- {
- DialogManager dlgMgr = Application.getDialogManager();
- objectForStack = dlgMgr.getState();
- }
- else if (viewId.equals(wizardContainer))
- {
- WizardManager wizMgr = Application.getWizardManager();
- objectForStack = wizMgr.getState();
- }
- else
- {
- objectForStack = viewId;
- }
-
- // if the stack is currently empty add the item
- Stack stack = getViewStack(context);
- if (stack.empty())
- {
- stack.push(objectForStack);
-
- if (logger.isDebugEnabled())
- logger.debug("Pushed item to view stack: " + objectForStack);
- }
- else
- {
- // if the item to go on to the stack and the top of
- // stack are both Strings and equals to each other
- // don't add anything to the stack to stop it
- // growing unecessarily
- Object topOfStack = stack.peek();
- if (objectForStack instanceof String &&
- topOfStack instanceof String &&
- topOfStack.equals(objectForStack))
- {
- if (logger.isDebugEnabled())
- logger.debug("current view is already top of the view stack!");
- }
- else
- {
- stack.push(objectForStack);
-
- if (logger.isDebugEnabled())
- logger.debug("Pushed item to view stack: " + objectForStack);
- }
- }
- }
-
- /**
- * Navigates to the appropriate page using the original navigation handler
- *
- * @param context FacesContext
- * @param fromAction The fromAction
- * @param outcome The outcome
- */
- private void navigate(FacesContext context, String fromAction, String outcome)
- {
- if (logger.isDebugEnabled())
- logger.debug("Passing outcome '" + outcome + "' to original navigation handler");
-
- this.origHandler.handleNavigation(context, fromAction, outcome);
- }
-
- /**
- * Dispatches to the given view id
- *
- * @param context Faces context
- * @param viewId The view id to go to
- */
- private void goToView(FacesContext context, String viewId)
- {
- ViewHandler viewHandler = context.getApplication().getViewHandler();
- UIViewRoot viewRoot = viewHandler.createView(context, viewId);
- viewRoot.setViewId(viewId);
- context.setViewRoot(viewRoot);
- context.renderResponse();
- }
-
- /**
- * Returns the view stack for the current user.
- *
- * @param context FacesContext
- * @return A Stack representing the views that have launched dialogs in
- * the users session, will never be null
- */
- @SuppressWarnings("unchecked")
- private Stack getViewStack(FacesContext context)
- {
- Stack viewStack = (Stack)context.getExternalContext().getSessionMap().get(VIEW_STACK);
-
- if (viewStack == null)
- {
- viewStack = new Stack();
- context.getExternalContext().getSessionMap().put(VIEW_STACK, viewStack);
- }
-
- return viewStack;
- }
-}
+package org.alfresco.web.app;
+
+import java.util.Stack;
+
+import javax.faces.application.NavigationHandler;
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+
+import org.springframework.extensions.config.Config;
+import org.springframework.extensions.config.ConfigService;
+import org.alfresco.service.cmr.repository.InvalidNodeRefException;
+import org.alfresco.web.app.servlet.FacesHelper;
+import org.alfresco.web.bean.NavigationBean;
+import org.alfresco.web.bean.dialog.DialogManager;
+import org.alfresco.web.bean.dialog.DialogState;
+import org.alfresco.web.bean.repository.Node;
+import org.alfresco.web.bean.wizard.WizardManager;
+import org.alfresco.web.bean.wizard.WizardState;
+import org.alfresco.web.config.DialogsConfigElement;
+import org.alfresco.web.config.NavigationConfigElement;
+import org.alfresco.web.config.NavigationElementReader;
+import org.alfresco.web.config.NavigationResult;
+import org.alfresco.web.config.WizardsConfigElement;
+import org.alfresco.web.config.DialogsConfigElement.DialogConfig;
+import org.alfresco.web.config.WizardsConfigElement.WizardConfig;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author gavinc
+ */
+public class AlfrescoNavigationHandler extends NavigationHandler
+{
+ public final static String OUTCOME_SEPARATOR = ":";
+ public final static String OUTCOME_BROWSE = "browse";
+ public final static String DIALOG_PREFIX = "dialog" + OUTCOME_SEPARATOR;
+ public final static String WIZARD_PREFIX = "wizard" + OUTCOME_SEPARATOR;
+ public final static String CLOSE_DIALOG_OUTCOME = DIALOG_PREFIX + "close";
+ public final static String CLOSE_WIZARD_OUTCOME = WIZARD_PREFIX + "close";
+ public final static String CLOSE_MULTIPLE_START = "[";
+ public final static String CLOSE_MULTIPLE_END = "]";
+ public final static String EXTERNAL_CONTAINER_SESSION = "externalDialogContainer";
+
+ protected String dialogContainer = null;
+ protected String wizardContainer = null;
+ protected String plainDialogContainer = null;
+ protected String plainWizardContainer = null;
+
+ private final static Log logger = LogFactory.getLog(AlfrescoNavigationHandler.class);
+ private final static String VIEW_STACK = "_alfViewStack";
+
+ // The original navigation handler
+ private NavigationHandler origHandler;
+
+ /**
+ * Default constructor
+ *
+ * @param origHandler The original navigation handler
+ */
+ public AlfrescoNavigationHandler(NavigationHandler origHandler)
+ {
+ super();
+ this.origHandler = origHandler;
+ }
+
+ /**
+ * @see javax.faces.application.NavigationHandler#handleNavigation(javax.faces.context.FacesContext, java.lang.String, java.lang.String)
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public void handleNavigation(FacesContext context, String fromAction, String outcome)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("handleNavigation (fromAction=" + fromAction + ", outcome=" + outcome + ")");
+ logger.debug("Current view id: " + context.getViewRoot().getViewId());
+ }
+
+ boolean isDialog = isDialog(outcome);
+ if (isDialog || isWizard(outcome))
+ {
+ boolean dialogWizardClosing = isDialogOrWizardClosing(outcome);
+ outcome = stripPrefix(outcome);
+
+ if (dialogWizardClosing)
+ {
+ handleDialogOrWizardClose(context, fromAction, outcome, isDialog);
+ }
+ else
+ {
+ if (isDialog)
+ {
+ handleDialogOpen(context, fromAction, outcome);
+ }
+ else
+ {
+ handleWizardOpen(context, fromAction, outcome);
+ }
+ }
+ }
+ else
+ {
+ if (isWizardStep(fromAction))
+ {
+ goToView(context, getWizardContainer(context));
+ }
+ else
+ {
+ handleDispatch(context, fromAction, outcome);
+ }
+ }
+
+ // reset the dispatch context
+ Object bean = FacesHelper.getManagedBean(context, NavigationBean.BEAN_NAME);
+ if (bean instanceof NavigationBean)
+ {
+ ((NavigationBean)bean).resetDispatchContext();
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("view stack: " + getViewStack(context));
+ }
+
+ /**
+ * Determines whether the given outcome is dialog related
+ *
+ * @param outcome The outcome to test
+ * @return true if outcome is dialog related i.e. starts with dialog:
+ */
+ protected boolean isDialog(String outcome)
+ {
+ boolean dialog = false;
+
+ if (outcome != null && outcome.startsWith(DIALOG_PREFIX))
+ {
+ dialog = true;
+ }
+
+ return dialog;
+ }
+
+ /**
+ * Determines whether the given outcome is wizard related
+ *
+ * @param outcome The outcome to test
+ * @return true if outcome is wizard related
+ * i.e. starts with create-wizard: or edit-wizard:
+ */
+ protected boolean isWizard(String outcome)
+ {
+ boolean wizard = false;
+
+ if (outcome != null && outcome.startsWith(WIZARD_PREFIX))
+ {
+ wizard = true;
+ }
+
+ return wizard;
+ }
+
+ /**
+ * Determines whether the given outcome represents a dialog or wizard closing
+ *
+ * @param outcome The outcome to test
+ * @return true if the outcome represents a closing dialog or wizard
+ */
+ protected boolean isDialogOrWizardClosing(String outcome)
+ {
+ boolean closing = false;
+
+ if (outcome != null &&
+ (outcome.startsWith(CLOSE_DIALOG_OUTCOME) ||
+ outcome.startsWith(CLOSE_WIZARD_OUTCOME)))
+ {
+ closing = true;
+ }
+
+ return closing;
+ }
+
+ protected int getNumberToClose(String outcome)
+ {
+ int toClose = 1;
+
+ int idxStart = outcome.indexOf(CLOSE_MULTIPLE_START);
+ if (outcome != null && idxStart != -1)
+ {
+ int idxEnd = outcome.indexOf(CLOSE_MULTIPLE_END);
+ if (idxEnd != -1)
+ {
+ String closeNum = outcome.substring(idxStart+1, idxEnd);
+ try
+ {
+ toClose = Integer.parseInt(closeNum);
+ }
+ catch (NumberFormatException nfe)
+ {
+ if (logger.isWarnEnabled())
+ logger.warn("Could not determine number of containers to close, defaulting to 1");
+ }
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Closing " + toClose + " levels of container");
+ }
+
+ return toClose;
+ }
+
+ /**
+ * Determines whether the given fromAction represents a step in the wizard
+ * i.e. next or back
+ *
+ * @param fromAction The fromAction
+ * @return true if the from action represents a wizard step
+ */
+ protected boolean isWizardStep(String fromAction)
+ {
+ boolean wizardStep = false;
+
+ if (fromAction != null &&
+ (fromAction.equals("#{WizardManager.next}") || fromAction.equals("#{WizardManager.back}")))
+ {
+ wizardStep = true;
+ }
+
+ return wizardStep;
+ }
+
+ /**
+ * Removes the dialog or wizard prefix from the given outcome
+ *
+ * @param outcome The outcome to remove the prefix from
+ * @return The remaining outcome
+ */
+ protected String stripPrefix(String outcome)
+ {
+ String newOutcome = outcome;
+
+ if (outcome != null)
+ {
+ int idx = outcome.indexOf(OUTCOME_SEPARATOR);
+ if (idx != -1)
+ {
+ newOutcome = outcome.substring(idx+1);
+ }
+ }
+
+ return newOutcome;
+ }
+
+ /**
+ * Returns the overridden outcome.
+ * Used by dialogs and wizards to go to a particular page after it closes
+ * rather than back to the page it was launched from.
+ *
+ * @param outcome The current outcome
+ * @return The overridden outcome or null if there isn't an override
+ */
+ protected String getOutcomeOverride(String outcome)
+ {
+ String override = null;
+
+ if (outcome != null)
+ {
+ int idx = outcome.indexOf(OUTCOME_SEPARATOR);
+ if (idx != -1)
+ {
+ override = outcome.substring(idx+1);
+ }
+ }
+
+ return override;
+ }
+
+ /**
+ * Returns the dialog configuration object for the given dialog name.
+ * If there is a node in the dispatch context a lookup is performed using
+ * the node otherwise the global config section is used.
+ *
+ *
+ * @param name The name of dialog being launched
+ * @param dispatchContext The node being acted upon
+ * @return The DialogConfig for the dialog or null if no config could be found
+ */
+ protected DialogConfig getDialogConfig(FacesContext context, String name, Node dispatchContext)
+ {
+ DialogConfig dialogConfig = null;
+ ConfigService configSvc = Application.getConfigService(context);
+
+ Config config = null;
+
+ if (dispatchContext != null)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Using dispatch context for dialog lookup: " +
+ dispatchContext.getType().toString());
+
+ // use the node to perform the lookup (this will include the global section)
+ config = configSvc.getConfig(dispatchContext);
+ }
+ else
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Looking up dialog in global config");
+
+ // just use the global
+ config = configSvc.getGlobalConfig();
+ }
+
+ if (config != null)
+ {
+ DialogsConfigElement dialogsCfg = (DialogsConfigElement)config.getConfigElement(
+ DialogsConfigElement.CONFIG_ELEMENT_ID);
+ if (dialogsCfg != null)
+ {
+ dialogConfig = dialogsCfg.getDialog(name);
+ }
+ }
+
+ return dialogConfig;
+ }
+
+ /**
+ * Returns the wizard configuration object for the given wizard name.
+ * If there is a node in the dispatch context a lookup is performed using
+ * the node otherwise the global config section is used.
+ *
+ * @param name The name of wizard being launched
+ * @param dispatchContext The node being acted upon
+ * @return The WizardConfig for the wizard or null if no config could be found
+ */
+ protected WizardConfig getWizardConfig(FacesContext context, String name, Node dispatchContext)
+ {
+ WizardConfig wizardConfig = null;
+ ConfigService configSvc = Application.getConfigService(context);
+
+ Config config = null;
+
+ if (dispatchContext != null)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Using dispatch context for wizard lookup: " +
+ dispatchContext.getType().toString());
+
+ // use the node to perform the lookup (this will include the global section)
+ config = configSvc.getConfig(dispatchContext);
+ }
+ else
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Looking up wizard in global config");
+
+ // just use the global
+ config = configSvc.getGlobalConfig();
+ }
+
+ if (config != null)
+ {
+ WizardsConfigElement wizardsCfg = (WizardsConfigElement)config.getConfigElement(
+ WizardsConfigElement.CONFIG_ELEMENT_ID);
+ if (wizardsCfg != null)
+ {
+ wizardConfig = wizardsCfg.getWizard(name);
+ }
+ }
+
+ return wizardConfig;
+ }
+
+ /**
+ * Retrieves the configured dialog container page
+ *
+ * @param context FacesContext
+ * @return The container page
+ */
+ protected String getDialogContainer(FacesContext context)
+ {
+ String container;
+
+ // determine which kind of container we need to return, if the
+ // external session flag is set then use the plain container
+ Object obj = context.getExternalContext().getSessionMap().get(EXTERNAL_CONTAINER_SESSION);
+
+ if (obj != null && obj instanceof Boolean && ((Boolean)obj).booleanValue())
+ {
+ if ((this.plainDialogContainer == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
+ {
+ ConfigService configSvc = Application.getConfigService(context);
+ Config globalConfig = configSvc.getGlobalConfig();
+
+ if (globalConfig != null)
+ {
+ this.plainDialogContainer = globalConfig.getConfigElement("plain-dialog-container").getValue();
+ }
+ }
+
+ container = this.plainDialogContainer;
+ }
+ else
+ {
+ if ((this.dialogContainer == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
+ {
+ ConfigService configSvc = Application.getConfigService(context);
+ Config globalConfig = configSvc.getGlobalConfig();
+
+ if (globalConfig != null)
+ {
+ this.dialogContainer = globalConfig.getConfigElement("dialog-container").getValue();
+ }
+ }
+
+ container = this.dialogContainer;
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Using dialog container: " + container);
+
+ return container;
+ }
+
+ /**
+ * Retrieves the configured wizard container page
+ *
+ * @param context FacesContext
+ * @return The container page
+ */
+ protected String getWizardContainer(FacesContext context)
+ {
+ String container;
+
+ // determine which kind of container we need to return, if the
+ // external session flag is set then use the plain container
+ Object obj = context.getExternalContext().getSessionMap().get(EXTERNAL_CONTAINER_SESSION);
+
+ if (obj != null && obj instanceof Boolean && ((Boolean)obj).booleanValue())
+ {
+ if ((this.plainWizardContainer == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
+ {
+ ConfigService configSvc = Application.getConfigService(context);
+ Config globalConfig = configSvc.getGlobalConfig();
+
+ if (globalConfig != null)
+ {
+ this.plainWizardContainer = globalConfig.getConfigElement("plain-wizard-container").getValue();
+ }
+ }
+
+ container = this.plainWizardContainer;
+ }
+ else
+ {
+ if ((this.wizardContainer == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
+ {
+ ConfigService configSvc = Application.getConfigService(context);
+ Config globalConfig = configSvc.getGlobalConfig();
+
+ if (globalConfig != null)
+ {
+ this.wizardContainer = globalConfig.getConfigElement("wizard-container").getValue();
+ }
+ }
+
+ container = this.wizardContainer;
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Using wizard container: " + container);
+
+ return container;
+ }
+
+ /**
+ * Returns the node currently in the dispatch context
+ *
+ * @return The node currently in the dispatch context or null if
+ * the dispatch context is empty
+ */
+ protected Node getDispatchContextNode(FacesContext context)
+ {
+ Node dispatchNode = null;
+
+ NavigationBean navBean = (NavigationBean)context.getExternalContext().
+ getSessionMap().get(NavigationBean.BEAN_NAME);
+
+ if (navBean != null)
+ {
+ dispatchNode = navBean.getDispatchContextNode();
+ }
+
+ return dispatchNode;
+ }
+
+ protected void handleBrowseDispatch(FacesContext context, String fromAction, String outcome)
+ {
+ Node dispatchNode = null;
+
+ NavigationBean navBean = (NavigationBean) context.getExternalContext().getSessionMap()
+ .get(NavigationBean.BEAN_NAME);
+
+ if (navBean != null)
+ {
+ dispatchNode = navBean.getCurrentNode();
+ }
+
+ handleDispatch(context, fromAction, outcome, dispatchNode);
+ }
+
+ /**
+ * Processes any dispatching that may need to occur
+ *
+ * @param context Faces context
+ * @param fromAction The from action
+ * @param outcome The outcome
+ */
+ protected void handleDispatch(FacesContext context, String fromAction, String outcome)
+ {
+ Node dispatchNode = getDispatchContextNode(context);
+ handleDispatch(context, fromAction, outcome, dispatchNode);
+ }
+
+ private void handleDispatch(FacesContext context, String fromAction, String outcome, Node dispatchNode)
+ {
+ if (dispatchNode != null)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Found node with type '" + dispatchNode.getType().toString() +
+ "' in dispatch context");
+
+ // get the current view id
+ String viewId = context.getViewRoot().getViewId();
+
+ // see if there is any navigation config for the node type
+ ConfigService configSvc = Application.getConfigService(context);
+ NavigationConfigElement navigationCfg = null;
+ try
+ {
+ Config nodeConfig = configSvc.getConfig(dispatchNode);
+ navigationCfg = (NavigationConfigElement)nodeConfig.
+ getConfigElement(NavigationElementReader.ELEMENT_NAVIGATION);
+ }
+ catch (InvalidNodeRefException e)
+ {
+ if (logger.isDebugEnabled()) logger.debug("Invalid node reference: " + dispatchNode);
+ }
+
+ if (navigationCfg != null)
+ {
+ // see if there is config for the current view state
+ NavigationResult navResult = navigationCfg.getOverride(viewId, outcome);
+
+ if (navResult != null)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Found navigation config: " + navResult);
+
+ if (navResult.isOutcome())
+ {
+ navigate(context, fromAction, navResult.getResult());
+ }
+ else
+ {
+ String newViewId = navResult.getResult();
+
+ if (newViewId.equals(viewId) == false)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Dispatching to new view id: " + newViewId);
+
+ goToView(context, newViewId);
+ }
+ else
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("New view id is the same as the current one so setting outcome to null");
+
+ navigate(context, fromAction, null);
+ }
+ }
+ }
+ else
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("No override configuration found for current view or outcome");
+
+ navigate(context, fromAction, outcome);
+ }
+ }
+ else
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("No navigation configuration found for node");
+
+ navigate(context, fromAction, outcome);
+ }
+
+ // reset the dispatch context
+ ((NavigationBean)context.getExternalContext().getSessionMap().
+ get(NavigationBean.BEAN_NAME)).resetDispatchContext();
+ }
+ else
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("No dispatch context found");
+
+ // pass off to the original handler
+ navigate(context, fromAction, outcome);
+ }
+ }
+
+ /**
+ * Opens a dialog
+ *
+ * @param context FacesContext
+ * @param fromAction The fromAction
+ * @param name The name of the dialog to open
+ */
+ protected void handleDialogOpen(FacesContext context, String fromAction, String name)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Opening dialog '" + name + "'");
+
+ // firstly add the current view to the stack so we know where to go back to
+ addCurrentViewToStack(context);
+
+ DialogConfig config = getDialogConfig(context, name, getDispatchContextNode(context));
+ if (config != null)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Found config for dialog '" + name + "': " + config);
+
+ // set the dialog manager up with the retrieved config
+ DialogManager dialogManager = Application.getDialogManager();
+ dialogManager.setCurrentDialog(config);
+
+ // retrieve the container page and navigate to it
+ goToView(context, getDialogContainer(context));
+ }
+ else
+ {
+ //logger.warn("Failed to find configuration for dialog '" + name + "'");
+
+ // send the dialog name as the outcome to the original handler
+ handleDispatch(context, fromAction, name);
+ }
+ }
+
+ /**
+ * Opens a wizard
+ *
+ * @param context FacesContext
+ * @param fromAction The fromAction
+ * @param name The name of the wizard to open
+ */
+ protected void handleWizardOpen(FacesContext context, String fromAction, String name)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Opening wizard '" + name + "'");
+
+ // firstly add the current view to the stack so we know where to go back to
+ addCurrentViewToStack(context);
+
+ WizardConfig wizard = getWizardConfig(context, name, getDispatchContextNode(context));
+ if (wizard != null)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Found config for wizard '" + name + "': " + wizard);
+
+ // set the wizard manager up with the retrieved config
+ WizardManager wizardManager = Application.getWizardManager();
+ wizardManager.setCurrentWizard(wizard);
+
+ // retrieve the container page and navigate to it
+ goToView(context, getWizardContainer(context));
+ }
+ else
+ {
+ //logger.warn("Failed to find configuration for wizard '" + name + "'");
+
+ // send the dialog name as the outcome to the original handler
+ handleDispatch(context, fromAction, name);
+ }
+ }
+
+ /**
+ * Closes the current dialog or wizard
+ *
+ * @param context FacesContext
+ * @param fromAction The fromAction
+ * @param outcome The outcome
+ * @param dialog true if a dialog is being closed, false if a wizard is being closed
+ */
+ protected void handleDialogOrWizardClose(FacesContext context, String fromAction, String outcome, boolean dialog)
+ {
+ String closingItem = dialog ? "dialog" : "wizard";
+
+ // if we are closing a wizard or dialog take the view off the
+ // top of the stack then decide whether to use the view
+ // or any overridden outcome that may be present
+ if (getViewStack(context).empty() == false)
+ {
+ // is there an overidden outcome?
+ String overriddenOutcome = getOutcomeOverride(outcome);
+ if (overriddenOutcome == null)
+ {
+ // there isn't an overidden outcome so go back to the previous view
+ if (logger.isDebugEnabled())
+ logger.debug("Closing " + closingItem);
+
+ // determine how many levels of dialog we need to close
+ int numberToClose = getNumberToClose(outcome);
+
+ Object stackObject = null;
+ if (numberToClose == 1)
+ {
+ // just closing one dialog so get the item from the top of the stack
+ stackObject = getViewStack(context).pop();
+
+ if (logger.isDebugEnabled())
+ logger.debug("Popped item from the top of the view stack: " + stackObject);
+ }
+ else
+ {
+ // check there are enough items on the stack, if there
+ // isn't just get the last one (effectively going back
+ // to the beginning)
+ Stack viewStack = getViewStack(context);
+ int itemsOnStack = viewStack.size();
+ if (itemsOnStack < numberToClose)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Returning to first item on the view stack as there aren't " +
+ numberToClose + " containers to close!");
+
+ numberToClose = itemsOnStack;
+ }
+
+ // pop the right object from the stack
+ for (int x = 1; x <= numberToClose; x++)
+ {
+ stackObject = viewStack.pop();
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Popped item from the stack: " + stackObject);
+ }
+
+ // get the appropriate view id for the stack object
+ String newViewId = getViewIdFromStackObject(context, stackObject);
+
+ // go to the appropraite page
+ goToView(context, newViewId);
+ }
+ else
+ {
+ // we also need to empty the dialog stack if we have been given
+ // an overidden outcome as we could be going anywhere in the app.
+ // grab the current top item first though in case we need to open
+ // another dialog or wizard
+ if (OUTCOME_BROWSE.equals(overriddenOutcome) == false)
+ {
+ String previousViewId = getViewIdFromStackObject(context, getViewStack(context).peek());
+ getViewStack(context).clear();
+
+ if (logger.isDebugEnabled())
+ logger.debug("Closing " + closingItem + " with an overridden outcome of '" + overriddenOutcome + "'");
+
+ // if the override is calling another dialog or wizard come back through
+ // the navigation handler from the beginning
+ if (isDialog(overriddenOutcome) || isWizard(overriddenOutcome))
+ {
+ // set the view id to the page at the top of the stack so when
+ // the new dialog or wizard closes it goes back to the correct page
+ context.getViewRoot().setViewId(previousViewId);
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("view stack: " + getViewStack(context));
+ logger.debug("Opening '" + overriddenOutcome + "' after " + closingItem +
+ " close using view id: " + previousViewId);
+ }
+
+ this.handleNavigation(context, fromAction, overriddenOutcome);
+ }
+ else
+ {
+ navigate(context, fromAction, overriddenOutcome);
+ }
+ }
+ else
+ {
+ handleBrowseDispatch(context, fromAction, overriddenOutcome);
+
+ // ALF-6661, always clear the view stack with an overridden outcome
+ getViewStack(context).clear();
+ }
+ }
+ }
+ else
+ {
+ // we are trying to close a dialog when one hasn't been opened!
+ // return to the main page of the app (print warning if debug is enabled)
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Attempting to close a " + closingItem + " with an empty view stack, returning 'browse' outcome");
+ }
+
+ navigate(context, fromAction, OUTCOME_BROWSE);
+ }
+ }
+
+ /**
+ * Returns the view id of the given item retrieved from the view stack.
+ *
+ * @param context FacesContext
+ * @param topOfStack The object retrieved from the view stack
+ * @return The view id
+ */
+ protected String getViewIdFromStackObject(FacesContext context, Object topOfStack)
+ {
+ String viewId = null;
+
+ // if the top of the stack is not a dialog or wizard just get the
+ // view id and navigate back to it.
+
+ // if the top of the stack is a dialog or wizard retrieve the state
+ // and setup the appropriate manager with that state, then get the
+ // appropriate container page and navigate to it.
+
+ if (topOfStack instanceof String)
+ {
+ viewId = (String)topOfStack;
+ }
+ else if (topOfStack instanceof DialogState)
+ {
+ // restore the dialog state and get the dialog container viewId
+ Application.getDialogManager().restoreState((DialogState)topOfStack);
+ viewId = getDialogContainer(context);
+ }
+ else if (topOfStack instanceof WizardState)
+ {
+ // restore the wizard state and get the wizard container viewId
+ Application.getWizardManager().restoreState((WizardState)topOfStack);
+ viewId = getWizardContainer(context);
+ }
+ else
+ {
+ if (logger.isWarnEnabled())
+ logger.warn("Invalid object found on view stack: " + topOfStack);
+ }
+
+ return viewId;
+ }
+
+ /**
+ * Adds the current view to the stack (if required).
+ * If the current view is already the top of the stack it is not added again
+ * to stop the stack from growing and growing.
+ *
+ * @param context FacesContext
+ */
+ @SuppressWarnings("unchecked")
+ protected void addCurrentViewToStack(FacesContext context)
+ {
+ // if the current viewId is either the dialog or wizard container page
+ // we need to save the state of the current dialog or wizard to the stack
+
+ // If the current view is a normal page and it is not the same as the
+ // view currently at the top of the stack (you can't launch a dialog from
+ // the same page 2 times in a row so it must mean the user navigated away
+ // from the first dialog) just add the viewId to the stack
+
+ // work out what to add to the stack
+ String viewId = context.getViewRoot().getViewId();
+ String dialogContainer = getDialogContainer(context);
+ String wizardContainer = getWizardContainer(context);
+ Object objectForStack = null;
+ if (viewId.equals(dialogContainer))
+ {
+ DialogManager dlgMgr = Application.getDialogManager();
+ objectForStack = dlgMgr.getState();
+ }
+ else if (viewId.equals(wizardContainer))
+ {
+ WizardManager wizMgr = Application.getWizardManager();
+ objectForStack = wizMgr.getState();
+ }
+ else
+ {
+ objectForStack = viewId;
+ }
+
+ // if the stack is currently empty add the item
+ Stack stack = getViewStack(context);
+ if (stack.empty())
+ {
+ stack.push(objectForStack);
+
+ if (logger.isDebugEnabled())
+ logger.debug("Pushed item to view stack: " + objectForStack);
+ }
+ else
+ {
+ // if the item to go on to the stack and the top of
+ // stack are both Strings and equals to each other
+ // don't add anything to the stack to stop it
+ // growing unecessarily
+ Object topOfStack = stack.peek();
+ if (objectForStack instanceof String &&
+ topOfStack instanceof String &&
+ topOfStack.equals(objectForStack))
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("current view is already top of the view stack!");
+ }
+ else
+ {
+ stack.push(objectForStack);
+
+ if (logger.isDebugEnabled())
+ logger.debug("Pushed item to view stack: " + objectForStack);
+ }
+ }
+ }
+
+ /**
+ * Navigates to the appropriate page using the original navigation handler
+ *
+ * @param context FacesContext
+ * @param fromAction The fromAction
+ * @param outcome The outcome
+ */
+ private void navigate(FacesContext context, String fromAction, String outcome)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Passing outcome '" + outcome + "' to original navigation handler");
+
+ this.origHandler.handleNavigation(context, fromAction, outcome);
+ }
+
+ /**
+ * Dispatches to the given view id
+ *
+ * @param context Faces context
+ * @param viewId The view id to go to
+ */
+ private void goToView(FacesContext context, String viewId)
+ {
+ ViewHandler viewHandler = context.getApplication().getViewHandler();
+ UIViewRoot viewRoot = viewHandler.createView(context, viewId);
+ viewRoot.setViewId(viewId);
+ context.setViewRoot(viewRoot);
+ context.renderResponse();
+ }
+
+ /**
+ * Returns the view stack for the current user.
+ *
+ * @param context FacesContext
+ * @return A Stack representing the views that have launched dialogs in
+ * the users session, will never be null
+ */
+ @SuppressWarnings("unchecked")
+ private Stack getViewStack(FacesContext context)
+ {
+ Stack viewStack = (Stack)context.getExternalContext().getSessionMap().get(VIEW_STACK);
+
+ if (viewStack == null)
+ {
+ viewStack = new Stack();
+ context.getExternalContext().getSessionMap().put(VIEW_STACK, viewStack);
+ }
+
+ return viewStack;
+ }
+}
diff --git a/source/java/org/alfresco/web/app/AlfrescoVariableResolver.java b/source/java/org/alfresco/web/app/AlfrescoVariableResolver.java
index c67dbb7b7f..b9c4488132 100644
--- a/source/java/org/alfresco/web/app/AlfrescoVariableResolver.java
+++ b/source/java/org/alfresco/web/app/AlfrescoVariableResolver.java
@@ -1,152 +1,152 @@
-package org.alfresco.web.app;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.faces.context.FacesContext;
-import javax.faces.el.EvaluationException;
-import javax.faces.el.VariableResolver;
-
-import org.springframework.extensions.config.Config;
-import org.springframework.extensions.config.ConfigService;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.web.jsf.DelegatingVariableResolver;
-
-/**
- * JSF VariableResolver that first delegates to the Spring JSF variable
- * resolver. The sole purpose of this variable resolver is to look out
- * for the Container variable. If this variable is encountered
- * the current viewId is examined. If the current viewId matches a
- * configured dialog or wizard container the appropriate manager object is
- * returned i.e. DialogManager or WizardManager.
- *
- *
Configure this resolver in your faces-config.xml file as follows:
- *
- *
- *
- * @see org.alfresco.web.bean.dialog.DialogManager
- * @see org.alfresco.web.bean.wizard.WizardManager
- * @author gavinc
- */
-public class AlfrescoVariableResolver extends DelegatingVariableResolver
-{
- protected List dialogContainers = null;
- protected List wizardContainers = null;
-
- private static final String CONTAINER = "Container";
-
- private static final Log logger = LogFactory.getLog(AlfrescoVariableResolver.class);
-
- /**
- * Creates a new VariableResolver.
- *
- * @param originalVariableResolver The original variable resolver
- */
- public AlfrescoVariableResolver(VariableResolver originalVariableResolver)
- {
- super(originalVariableResolver);
- }
-
- /**
- * Resolves the variable with the given name.
- *
- * This implementation will first delegate to the Spring variable resolver.
- * If the variable is not found by the Spring resolver and the variable name
- * is Container the current viewId is examined.
- * If the current viewId matches a configured dialog or wizard container
- * the appropriate manager object is returned i.e. DialogManager or WizardManager.
- *
- * @param context FacesContext
- * @param name The name of the variable to resolve
- */
- public Object resolveVariable(FacesContext context, String name)
- throws EvaluationException
- {
- Object variable = super.resolveVariable(context, name);
-
- if (variable == null)
- {
- // if the variable was not resolved see if the name is "Container"
- if (name.equals(CONTAINER))
- {
- // get the current view id and the configured dialog and wizard
- // container pages
- String viewId = context.getViewRoot().getViewId();
- List dialogContainers = getDialogContainers(context);
- List wizardContainers = getWizardContainers(context);
-
- // see if we are currently in a wizard or a dialog
- if (dialogContainers.contains(viewId))
- {
- variable = Application.getDialogManager();
- }
- else if (wizardContainers.contains(viewId))
- {
- variable = Application.getWizardManager();
- }
-
- if (variable != null && logger.isDebugEnabled())
- {
- logger.debug("Resolved 'Container' variable to: " + variable);
- }
- }
- }
-
- return variable;
- }
-
- /**
- * Retrieves the list of configured dialog container pages
- *
- * @param context FacesContext
- * @return The container pages
- */
- protected List getDialogContainers(FacesContext context)
- {
- if ((this.dialogContainers == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
- {
- this.dialogContainers = new ArrayList(2);
-
- ConfigService configSvc = Application.getConfigService(context);
- Config globalConfig = configSvc.getGlobalConfig();
-
- if (globalConfig != null)
- {
- this.dialogContainers.add(globalConfig.getConfigElement("dialog-container").getValue());
- this.dialogContainers.add(globalConfig.getConfigElement("plain-dialog-container").getValue());
- }
- }
-
- return this.dialogContainers;
- }
-
- /**
- * Retrieves the list of configured wizard container pages
- *
- * @param context FacesContext
- * @return The container page
- */
- protected List getWizardContainers(FacesContext context)
- {
- if ((this.wizardContainers == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
- {
- this.wizardContainers = new ArrayList(2);
-
- ConfigService configSvc = Application.getConfigService(context);
- Config globalConfig = configSvc.getGlobalConfig();
-
- if (globalConfig != null)
- {
- this.wizardContainers.add(globalConfig.getConfigElement("wizard-container").getValue());
- this.wizardContainers.add(globalConfig.getConfigElement("plain-wizard-container").getValue());
- }
- }
-
- return this.wizardContainers;
- }
-}
+package org.alfresco.web.app;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.faces.context.FacesContext;
+import javax.faces.el.EvaluationException;
+import javax.faces.el.VariableResolver;
+
+import org.springframework.extensions.config.Config;
+import org.springframework.extensions.config.ConfigService;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.web.jsf.DelegatingVariableResolver;
+
+/**
+ * JSF VariableResolver that first delegates to the Spring JSF variable
+ * resolver. The sole purpose of this variable resolver is to look out
+ * for the Container variable. If this variable is encountered
+ * the current viewId is examined. If the current viewId matches a
+ * configured dialog or wizard container the appropriate manager object is
+ * returned i.e. DialogManager or WizardManager.
+ *
+ *
Configure this resolver in your faces-config.xml file as follows:
+ *
+ *
+ *
+ * @see org.alfresco.web.bean.dialog.DialogManager
+ * @see org.alfresco.web.bean.wizard.WizardManager
+ * @author gavinc
+ */
+public class AlfrescoVariableResolver extends DelegatingVariableResolver
+{
+ protected List dialogContainers = null;
+ protected List wizardContainers = null;
+
+ private static final String CONTAINER = "Container";
+
+ private static final Log logger = LogFactory.getLog(AlfrescoVariableResolver.class);
+
+ /**
+ * Creates a new VariableResolver.
+ *
+ * @param originalVariableResolver The original variable resolver
+ */
+ public AlfrescoVariableResolver(VariableResolver originalVariableResolver)
+ {
+ super(originalVariableResolver);
+ }
+
+ /**
+ * Resolves the variable with the given name.
+ *
+ * This implementation will first delegate to the Spring variable resolver.
+ * If the variable is not found by the Spring resolver and the variable name
+ * is Container the current viewId is examined.
+ * If the current viewId matches a configured dialog or wizard container
+ * the appropriate manager object is returned i.e. DialogManager or WizardManager.
+ *
+ * @param context FacesContext
+ * @param name The name of the variable to resolve
+ */
+ public Object resolveVariable(FacesContext context, String name)
+ throws EvaluationException
+ {
+ Object variable = super.resolveVariable(context, name);
+
+ if (variable == null)
+ {
+ // if the variable was not resolved see if the name is "Container"
+ if (name.equals(CONTAINER))
+ {
+ // get the current view id and the configured dialog and wizard
+ // container pages
+ String viewId = context.getViewRoot().getViewId();
+ List dialogContainers = getDialogContainers(context);
+ List wizardContainers = getWizardContainers(context);
+
+ // see if we are currently in a wizard or a dialog
+ if (dialogContainers.contains(viewId))
+ {
+ variable = Application.getDialogManager();
+ }
+ else if (wizardContainers.contains(viewId))
+ {
+ variable = Application.getWizardManager();
+ }
+
+ if (variable != null && logger.isDebugEnabled())
+ {
+ logger.debug("Resolved 'Container' variable to: " + variable);
+ }
+ }
+ }
+
+ return variable;
+ }
+
+ /**
+ * Retrieves the list of configured dialog container pages
+ *
+ * @param context FacesContext
+ * @return The container pages
+ */
+ protected List getDialogContainers(FacesContext context)
+ {
+ if ((this.dialogContainers == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
+ {
+ this.dialogContainers = new ArrayList(2);
+
+ ConfigService configSvc = Application.getConfigService(context);
+ Config globalConfig = configSvc.getGlobalConfig();
+
+ if (globalConfig != null)
+ {
+ this.dialogContainers.add(globalConfig.getConfigElement("dialog-container").getValue());
+ this.dialogContainers.add(globalConfig.getConfigElement("plain-dialog-container").getValue());
+ }
+ }
+
+ return this.dialogContainers;
+ }
+
+ /**
+ * Retrieves the list of configured wizard container pages
+ *
+ * @param context FacesContext
+ * @return The container page
+ */
+ protected List getWizardContainers(FacesContext context)
+ {
+ if ((this.wizardContainers == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
+ {
+ this.wizardContainers = new ArrayList(2);
+
+ ConfigService configSvc = Application.getConfigService(context);
+ Config globalConfig = configSvc.getGlobalConfig();
+
+ if (globalConfig != null)
+ {
+ this.wizardContainers.add(globalConfig.getConfigElement("wizard-container").getValue());
+ this.wizardContainers.add(globalConfig.getConfigElement("plain-wizard-container").getValue());
+ }
+ }
+
+ return this.wizardContainers;
+ }
+}
diff --git a/source/java/org/alfresco/web/app/DebugPhaseListener.java b/source/java/org/alfresco/web/app/DebugPhaseListener.java
index 599127005b..6e41fb0764 100644
--- a/source/java/org/alfresco/web/app/DebugPhaseListener.java
+++ b/source/java/org/alfresco/web/app/DebugPhaseListener.java
@@ -1,99 +1,99 @@
-package org.alfresco.web.app;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.faces.component.UIComponent;
-import javax.faces.context.FacesContext;
-import javax.faces.event.PhaseEvent;
-import javax.faces.event.PhaseId;
-import javax.faces.event.PhaseListener;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Debug phase listener that simply logs when each phase is entered and exited.
- *
- * @author gavinc
- */
-public class DebugPhaseListener implements PhaseListener
-{
- private static final Log logger = LogFactory.getLog(DebugPhaseListener.class);
-
- public int indent = 0;
- public static final String INDENT = " ";
-
- /**
- * @see javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent)
- */
- public void afterPhase(PhaseEvent event)
- {
- if (logger.isDebugEnabled())
- {
- if (event.getPhaseId() == PhaseId.RENDER_RESPONSE)
- {
- printComponentTree(FacesContext.getCurrentInstance().getViewRoot());
- }
-
- logger.debug("********** Exiting phase: " + event.getPhaseId().toString());
- }
- }
-
- /**
- * @see javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
- */
- public void beforePhase(PhaseEvent event)
- {
- if (logger.isDebugEnabled())
- logger.debug("********** Entering phase: " + event.getPhaseId().toString());
- }
-
- /**
- * @see javax.faces.event.PhaseListener#getPhaseId()
- */
- public PhaseId getPhaseId()
- {
- return PhaseId.ANY_PHASE;
- }
-
- public void printComponentTree(UIComponent comp)
- {
- printComponentInfo(comp);
-
- List complist = comp.getChildren();
- if (complist.size()>0)
- indent++;
- for (int i = 0; i < complist.size(); i++)
- {
- UIComponent uicom = (UIComponent) complist.get(i);
- printComponentTree(uicom);
- if (i+1 == complist.size())
- indent--;
- }
- }
-
- public void printComponentInfo(UIComponent comp)
- {
- if (comp.getId() == null)
- {
- logger.debug("UIViewRoot" + " " + "(" + comp.getClass().getName() + ")");
- }
- else
- {
- logger.debug(getIndent() + "|");
- logger.debug(getIndent() + comp.getId() + " " + "(" + comp.getClass().getName() + ")");
- }
- }
-
- public String getIndent()
- {
- String indent = "";
- for (int i=0; i0)
+ indent++;
+ for (int i = 0; i < complist.size(); i++)
+ {
+ UIComponent uicom = (UIComponent) complist.get(i);
+ printComponentTree(uicom);
+ if (i+1 == complist.size())
+ indent--;
+ }
+ }
+
+ public void printComponentInfo(UIComponent comp)
+ {
+ if (comp.getId() == null)
+ {
+ logger.debug("UIViewRoot" + " " + "(" + comp.getClass().getName() + ")");
+ }
+ else
+ {
+ logger.debug(getIndent() + "|");
+ logger.debug(getIndent() + comp.getId() + " " + "(" + comp.getClass().getName() + ")");
+ }
+ }
+
+ public String getIndent()
+ {
+ String indent = "";
+ for (int i=0; i
- * This will show all debug entries from this class as though they
- * came from the subclass.
- *
- * @return The logger
- */
- protected abstract Log getLogger();
-
- /**
- * Processes the download request using the current context i.e. no authentication checks are made, it is presumed
- * they have already been done.
- *
- * @param req
- * The HTTP request
- * @param res
- * The HTTP response
- * @param allowLogIn
- * Indicates whether guest users without access to the content should be redirected to the log in page. If
- * false, a status 403 forbidden page is displayed instead.
- */
- protected void processDownloadRequest(HttpServletRequest req, HttpServletResponse res,
- boolean allowLogIn, boolean transmitContent)
- throws ServletException, IOException
- {
- Log logger = getLogger();
- String uri = req.getRequestURI();
-
- if (logger.isDebugEnabled())
- {
- String queryString = req.getQueryString();
- logger.debug("Processing URL: " + uri +
- ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
- }
-
- uri = uri.substring(req.getContextPath().length());
- StringTokenizer t = new StringTokenizer(uri, "/");
- int tokenCount = t.countTokens();
-
- t.nextToken(); // skip servlet name
-
- // attachment mode (either 'attach' or 'direct')
- String attachToken = t.nextToken();
- boolean attachment = URL_ATTACH.equals(attachToken) || URL_ATTACH_LONG.equals(attachToken);
-
- ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
-
- // get or calculate the noderef and filename to download as
- NodeRef nodeRef;
- String filename;
-
- // do we have a path parameter instead of a NodeRef?
- String path = req.getParameter(ARG_PATH);
- if (path != null && path.length() != 0)
- {
- // process the name based path to resolve the NodeRef and the Filename element
- try
- {
- PathRefInfo pathInfo = resolveNamePath(getServletContext(), path);
- nodeRef = pathInfo.NodeRef;
- filename = pathInfo.Filename;
- }
- catch (IllegalArgumentException e)
- {
- Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
- HttpServletResponse.SC_NOT_FOUND, logger);
- return;
- }
- }
- else
- {
- // a NodeRef must have been specified if no path has been found
- if (tokenCount < 6)
- {
- throw new IllegalArgumentException("Download URL did not contain all required args: " + uri);
- }
-
- // assume 'workspace' or other NodeRef based protocol for remaining URL elements
- StoreRef storeRef = new StoreRef(URLDecoder.decode(t.nextToken()), URLDecoder.decode(t.nextToken()));
- String id = URLDecoder.decode(t.nextToken());
-
- // build noderef from the appropriate URL elements
- nodeRef = new NodeRef(storeRef, id);
-
- if (tokenCount > 6)
- {
- // found additional relative path elements i.e. noderefid/images/file.txt
- // this allows a url to reference siblings nodes via a cm:name based relative path
- // solves the issue with opening HTML content containing relative URLs in HREF or IMG tags etc.
- List paths = new ArrayList(tokenCount - 5);
- while (t.hasMoreTokens())
- {
- paths.add(URLDecoder.decode(t.nextToken()));
- }
- filename = paths.get(paths.size() - 1);
-
- try
- {
- NodeRef parentRef = serviceRegistry.getNodeService().getPrimaryParent(nodeRef).getParentRef();
- FileInfo fileInfo = serviceRegistry.getFileFolderService().resolveNamePath(parentRef, paths);
- nodeRef = fileInfo.getNodeRef();
- }
- catch (FileNotFoundException e)
- {
- Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
- HttpServletResponse.SC_NOT_FOUND, logger);
- return;
- }
- }
- else
- {
- // filename is last remaining token
- filename = t.nextToken();
- }
- }
-
- // get qualified of the property to get content from - default to ContentModel.PROP_CONTENT
- QName propertyQName = ContentModel.PROP_CONTENT;
- String property = req.getParameter(ARG_PROPERTY);
- if (property != null && property.length() != 0)
- {
- propertyQName = QName.createQName(property);
- }
-
- if (logger.isDebugEnabled())
- {
- logger.debug("Found NodeRef: " + nodeRef);
- logger.debug("Will use filename: " + filename);
- logger.debug("For property: " + propertyQName);
- logger.debug("With attachment mode: " + attachment);
- }
-
- // get the services we need to retrieve the content
- NodeService nodeService = serviceRegistry.getNodeService();
- ContentService contentService = serviceRegistry.getContentService();
-
- // Check that the node still exists
- if (!nodeService.exists(nodeRef))
- {
- Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
- HttpServletResponse.SC_NOT_FOUND, logger);
- return;
- }
-
- try
- {
- // check that the user has at least READ_CONTENT access - else redirect to an error or login page
- if (!checkAccess(req, res, nodeRef, PermissionService.READ_CONTENT, allowLogIn))
- {
- return;
- }
-
- // check If-Modified-Since header and set Last-Modified header as appropriate
- Date modified = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED);
- if (modified != null)
- {
- long modifiedSince = req.getDateHeader(HEADER_IF_MODIFIED_SINCE);
- if (modifiedSince > 0L)
- {
- // round the date to the ignore millisecond value which is not supplied by header
- long modDate = (modified.getTime() / 1000L) * 1000L;
- if (modDate <= modifiedSince)
- {
- if (logger.isDebugEnabled())
- logger.debug("Returning 304 Not Modified.");
- res.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
- return;
- }
- }
- res.setDateHeader(HEADER_LAST_MODIFIED, modified.getTime());
- res.setHeader(HEADER_CACHE_CONTROL, "must-revalidate, max-age=0");
- res.setHeader(HEADER_ETAG, "\"" + Long.toString(modified.getTime()) + "\"");
- }
-
- if (attachment == true)
- {
- setHeaderContentDisposition(req, res, filename);
- }
-
- // get the content reader
- ContentReader reader = contentService.getReader(nodeRef, propertyQName);
- // ensure that it is safe to use
- reader = FileContentReader.getSafeContentReader(
- reader,
- Application.getMessage(req.getSession(), MSG_ERROR_CONTENT_MISSING),
- nodeRef, reader);
-
- String mimetype = reader.getMimetype();
- // fall back if unable to resolve mimetype property
- if (mimetype == null || mimetype.length() == 0)
- {
- MimetypeService mimetypeMap = serviceRegistry.getMimetypeService();
- mimetype = MIMETYPE_OCTET_STREAM;
- int extIndex = filename.lastIndexOf('.');
- if (extIndex != -1)
- {
- String ext = filename.substring(extIndex + 1);
- mimetype = mimetypeMap.getMimetype(ext);
- }
- }
-
- // explicitly set the content disposition header if the content is powerpoint
- if (!attachment && (mimetype.equals(POWER_POINT_2007_DOCUMENT_MIMETYPE) ||
- mimetype.equals(POWER_POINT_DOCUMENT_MIMETYPE)))
- {
- setHeaderContentDisposition(req, res, filename);
- }
-
- // get the content and stream directly to the response output stream
- // assuming the repo is capable of streaming in chunks, this should allow large files
- // to be streamed directly to the browser response stream.
- res.setHeader(HEADER_ACCEPT_RANGES, "bytes");
-
- // for a GET request, transmit the content else just the headers are sent
- if (transmitContent)
- {
- try
- {
- boolean processedRange = false;
- String range = req.getHeader(HEADER_CONTENT_RANGE);
- if (range == null)
- {
- range = req.getHeader(HEADER_RANGE);
- }
- if (range != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("Found content range header: " + range);
-
- // ensure the range header is starts with "bytes=" and process the range(s)
- if (range.length() > 6)
- {
- HttpRangeProcessor rangeProcessor = new HttpRangeProcessor(contentService);
- processedRange = rangeProcessor.processRange(
- res, reader, range.substring(6), nodeRef, propertyQName,
- mimetype, req.getHeader(HEADER_USER_AGENT));
- }
- }
- if (processedRange == false)
- {
- if (logger.isDebugEnabled())
- logger.debug("Sending complete file content...");
-
- // set mimetype for the content and the character encoding for the stream
- res.setContentType(mimetype);
- res.setCharacterEncoding(reader.getEncoding());
-
- // MNT-10642 Alfresco Explorer has javascript vulnerability opening HTML files
- if (req.getRequestURI().contains("/d/d/") && (mimetype.equals("text/html") || mimetype.equals("application/xhtml+xml") || mimetype.equals("text/xml")))
- {
- String content = reader.getContentString();
-
- if (mimetype.equals("text/html") || mimetype.equals("application/xhtml+xml"))
- {
- // process with HTML stripper
- content = StringUtils.stripUnsafeHTMLTags(content, false);
- }
- else if (mimetype.equals("text/xml") && mimetype.equals("text/x-component"))
- {
- // IE supports "behaviour" which means that css can load a .htc file that could
- // contain XSS code in the form of jscript, vbscript etc, to stop it form being
- // evaluated we set the contient type to text/plain
- res.setContentType("text/plain");
- }
-
- String encoding = reader.getEncoding();
- byte[] bytes = encoding != null ? content.getBytes(encoding) : content.getBytes();
- res.setContentLength(bytes.length);
- res.getOutputStream().write(bytes);
-
- return;
- }
-
- // return the complete entity range
- long size = reader.getSize();
- res.setHeader(HEADER_CONTENT_RANGE, "bytes 0-" + Long.toString(size-1L) + "/" + Long.toString(size));
- res.setHeader(HEADER_CONTENT_LENGTH, Long.toString(size));
- reader.getContent( res.getOutputStream() );
- }
- }
- catch (SocketException e1)
- {
- // the client cut the connection - our mission was accomplished apart from a little error message
- if (logger.isDebugEnabled())
- logger.debug("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
- }
- catch (ContentIOException e2)
- {
- if (logger.isInfoEnabled())
- logger.info("Failed stream read:\n\tnode: " + nodeRef + " due to: " + e2.getMessage());
- }
- catch (Throwable err)
- {
- if (err.getCause() instanceof SocketException)
- {
- // the client cut the connection - our mission was accomplished apart from a little error message
- if (logger.isDebugEnabled())
- logger.debug("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
- }
- else throw err;
- }
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("HEAD request processed - no content sent.");
- res.getOutputStream().close();
- }
- }
- catch (Throwable err)
- {
- throw new AlfrescoRuntimeException("Error during download content servlet processing: " + err.getMessage(), err);
- }
- }
-
- private void setHeaderContentDisposition(HttpServletRequest req, HttpServletResponse res, String filename)
- {
- // set header based on filename - will force a Save As from the browse if it doesn't recognise it
- // this is better than the default response of the browser trying to display the contents
-
- // IE requires that "Content-Disposition" header in case of "attachment" type should include
- // "filename" part. See MNT-9900
- String userAgent = req.getHeader(HEADER_USER_AGENT);
- if (userAgent != null && (userAgent.toLowerCase().contains("firefox") || userAgent.toLowerCase().contains("safari")))
- {
- res.setHeader(HEADER_CONTENT_DISPOSITION, "attachment; filename=\"" + URLDecoder.decode(filename) + "\"");
- }
- else
- {
- res.setHeader(HEADER_CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"");
- }
-
- }
-
- /**
- * Helper to generate a URL to a content node for downloading content from the server.
- *
- * @param pattern The pattern to use for the URL
- * @param ref NodeRef of the content node to generate URL for (cannot be null)
- * @param name File name to return in the URL (cannot be null)
- *
- * @return URL to download the content from the specified node
- */
- protected final static String generateUrl(String pattern, NodeRef ref, String name)
- {
- return MessageFormat.format(pattern, new Object[] {
- ref.getStoreRef().getProtocol(),
- ref.getStoreRef().getIdentifier(),
- ref.getId(),
- URLEncoder.encode(name) } );
- }
-}
+package org.alfresco.web.app.servlet;
+
+import java.io.IOException;
+import java.net.SocketException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.content.filestore.FileContentReader;
+import org.alfresco.repo.web.util.HttpRangeProcessor;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.model.FileInfo;
+import org.alfresco.service.cmr.model.FileNotFoundException;
+import org.alfresco.service.cmr.repository.ContentIOException;
+import org.alfresco.service.cmr.repository.ContentReader;
+import org.alfresco.service.cmr.repository.ContentService;
+import org.alfresco.service.cmr.repository.MimetypeService;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.StoreRef;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.web.app.Application;
+import org.apache.commons.logging.Log;
+import org.springframework.extensions.surf.util.URLDecoder;
+import org.springframework.extensions.surf.util.URLEncoder;
+import org.springframework.extensions.webscripts.ui.common.StringUtils;
+
+/**
+ * Base class for the download content servlets. Provides common
+ * processing for the request.
+ *
+ * @see org.alfresco.web.app.servlet.DownloadContentServlet
+ * @see org.alfresco.web.app.servlet.GuestDownloadContentServlet
+ *
+ * @author Kevin Roast
+ * @author gavinc
+ */
+public abstract class BaseDownloadContentServlet extends BaseServlet
+{
+ private static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
+
+ private static final long serialVersionUID = -4558907921887235967L;
+
+ private static final String POWER_POINT_DOCUMENT_MIMETYPE = "application/vnd.ms-powerpoint";
+ private static final String POWER_POINT_2007_DOCUMENT_MIMETYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
+
+ private static final String HEADER_CONTENT_RANGE = "Content-Range";
+ private static final String HEADER_CONTENT_LENGTH = "Content-Length";
+ private static final String HEADER_ACCEPT_RANGES = "Accept-Ranges";
+ private static final String HEADER_RANGE = "Range";
+ private static final String HEADER_ETAG = "ETag";
+ private static final String HEADER_CACHE_CONTROL = "Cache-Control";
+ private static final String HEADER_LAST_MODIFIED = "Last-Modified";
+ private static final String HEADER_USER_AGENT = "User-Agent";
+ private static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
+
+ protected static final String MIMETYPE_OCTET_STREAM = "application/octet-stream";
+
+ protected static final String MSG_ERROR_CONTENT_MISSING = "error_content_missing";
+ protected static final String MSG_ERROR_NOT_FOUND = "error_not_found";
+
+ protected static final String URL_DIRECT = "d";
+ protected static final String URL_DIRECT_LONG = "direct";
+ protected static final String URL_ATTACH = "a";
+ protected static final String URL_ATTACH_LONG = "attach";
+ protected static final String ARG_PROPERTY = "property";
+ protected static final String ARG_PATH = "path";
+
+ /**
+ * Gets the logger to use for this request.
+ *
+ * This will show all debug entries from this class as though they
+ * came from the subclass.
+ *
+ * @return The logger
+ */
+ protected abstract Log getLogger();
+
+ /**
+ * Processes the download request using the current context i.e. no authentication checks are made, it is presumed
+ * they have already been done.
+ *
+ * @param req
+ * The HTTP request
+ * @param res
+ * The HTTP response
+ * @param allowLogIn
+ * Indicates whether guest users without access to the content should be redirected to the log in page. If
+ * false, a status 403 forbidden page is displayed instead.
+ */
+ protected void processDownloadRequest(HttpServletRequest req, HttpServletResponse res,
+ boolean allowLogIn, boolean transmitContent)
+ throws ServletException, IOException
+ {
+ Log logger = getLogger();
+ String uri = req.getRequestURI();
+
+ if (logger.isDebugEnabled())
+ {
+ String queryString = req.getQueryString();
+ logger.debug("Processing URL: " + uri +
+ ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
+ }
+
+ uri = uri.substring(req.getContextPath().length());
+ StringTokenizer t = new StringTokenizer(uri, "/");
+ int tokenCount = t.countTokens();
+
+ t.nextToken(); // skip servlet name
+
+ // attachment mode (either 'attach' or 'direct')
+ String attachToken = t.nextToken();
+ boolean attachment = URL_ATTACH.equals(attachToken) || URL_ATTACH_LONG.equals(attachToken);
+
+ ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
+
+ // get or calculate the noderef and filename to download as
+ NodeRef nodeRef;
+ String filename;
+
+ // do we have a path parameter instead of a NodeRef?
+ String path = req.getParameter(ARG_PATH);
+ if (path != null && path.length() != 0)
+ {
+ // process the name based path to resolve the NodeRef and the Filename element
+ try
+ {
+ PathRefInfo pathInfo = resolveNamePath(getServletContext(), path);
+ nodeRef = pathInfo.NodeRef;
+ filename = pathInfo.Filename;
+ }
+ catch (IllegalArgumentException e)
+ {
+ Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
+ HttpServletResponse.SC_NOT_FOUND, logger);
+ return;
+ }
+ }
+ else
+ {
+ // a NodeRef must have been specified if no path has been found
+ if (tokenCount < 6)
+ {
+ throw new IllegalArgumentException("Download URL did not contain all required args: " + uri);
+ }
+
+ // assume 'workspace' or other NodeRef based protocol for remaining URL elements
+ StoreRef storeRef = new StoreRef(URLDecoder.decode(t.nextToken()), URLDecoder.decode(t.nextToken()));
+ String id = URLDecoder.decode(t.nextToken());
+
+ // build noderef from the appropriate URL elements
+ nodeRef = new NodeRef(storeRef, id);
+
+ if (tokenCount > 6)
+ {
+ // found additional relative path elements i.e. noderefid/images/file.txt
+ // this allows a url to reference siblings nodes via a cm:name based relative path
+ // solves the issue with opening HTML content containing relative URLs in HREF or IMG tags etc.
+ List paths = new ArrayList(tokenCount - 5);
+ while (t.hasMoreTokens())
+ {
+ paths.add(URLDecoder.decode(t.nextToken()));
+ }
+ filename = paths.get(paths.size() - 1);
+
+ try
+ {
+ NodeRef parentRef = serviceRegistry.getNodeService().getPrimaryParent(nodeRef).getParentRef();
+ FileInfo fileInfo = serviceRegistry.getFileFolderService().resolveNamePath(parentRef, paths);
+ nodeRef = fileInfo.getNodeRef();
+ }
+ catch (FileNotFoundException e)
+ {
+ Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
+ HttpServletResponse.SC_NOT_FOUND, logger);
+ return;
+ }
+ }
+ else
+ {
+ // filename is last remaining token
+ filename = t.nextToken();
+ }
+ }
+
+ // get qualified of the property to get content from - default to ContentModel.PROP_CONTENT
+ QName propertyQName = ContentModel.PROP_CONTENT;
+ String property = req.getParameter(ARG_PROPERTY);
+ if (property != null && property.length() != 0)
+ {
+ propertyQName = QName.createQName(property);
+ }
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Found NodeRef: " + nodeRef);
+ logger.debug("Will use filename: " + filename);
+ logger.debug("For property: " + propertyQName);
+ logger.debug("With attachment mode: " + attachment);
+ }
+
+ // get the services we need to retrieve the content
+ NodeService nodeService = serviceRegistry.getNodeService();
+ ContentService contentService = serviceRegistry.getContentService();
+
+ // Check that the node still exists
+ if (!nodeService.exists(nodeRef))
+ {
+ Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
+ HttpServletResponse.SC_NOT_FOUND, logger);
+ return;
+ }
+
+ try
+ {
+ // check that the user has at least READ_CONTENT access - else redirect to an error or login page
+ if (!checkAccess(req, res, nodeRef, PermissionService.READ_CONTENT, allowLogIn))
+ {
+ return;
+ }
+
+ // check If-Modified-Since header and set Last-Modified header as appropriate
+ Date modified = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED);
+ if (modified != null)
+ {
+ long modifiedSince = req.getDateHeader(HEADER_IF_MODIFIED_SINCE);
+ if (modifiedSince > 0L)
+ {
+ // round the date to the ignore millisecond value which is not supplied by header
+ long modDate = (modified.getTime() / 1000L) * 1000L;
+ if (modDate <= modifiedSince)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Returning 304 Not Modified.");
+ res.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+ }
+ res.setDateHeader(HEADER_LAST_MODIFIED, modified.getTime());
+ res.setHeader(HEADER_CACHE_CONTROL, "must-revalidate, max-age=0");
+ res.setHeader(HEADER_ETAG, "\"" + Long.toString(modified.getTime()) + "\"");
+ }
+
+ if (attachment == true)
+ {
+ setHeaderContentDisposition(req, res, filename);
+ }
+
+ // get the content reader
+ ContentReader reader = contentService.getReader(nodeRef, propertyQName);
+ // ensure that it is safe to use
+ reader = FileContentReader.getSafeContentReader(
+ reader,
+ Application.getMessage(req.getSession(), MSG_ERROR_CONTENT_MISSING),
+ nodeRef, reader);
+
+ String mimetype = reader.getMimetype();
+ // fall back if unable to resolve mimetype property
+ if (mimetype == null || mimetype.length() == 0)
+ {
+ MimetypeService mimetypeMap = serviceRegistry.getMimetypeService();
+ mimetype = MIMETYPE_OCTET_STREAM;
+ int extIndex = filename.lastIndexOf('.');
+ if (extIndex != -1)
+ {
+ String ext = filename.substring(extIndex + 1);
+ mimetype = mimetypeMap.getMimetype(ext);
+ }
+ }
+
+ // explicitly set the content disposition header if the content is powerpoint
+ if (!attachment && (mimetype.equals(POWER_POINT_2007_DOCUMENT_MIMETYPE) ||
+ mimetype.equals(POWER_POINT_DOCUMENT_MIMETYPE)))
+ {
+ setHeaderContentDisposition(req, res, filename);
+ }
+
+ // get the content and stream directly to the response output stream
+ // assuming the repo is capable of streaming in chunks, this should allow large files
+ // to be streamed directly to the browser response stream.
+ res.setHeader(HEADER_ACCEPT_RANGES, "bytes");
+
+ // for a GET request, transmit the content else just the headers are sent
+ if (transmitContent)
+ {
+ try
+ {
+ boolean processedRange = false;
+ String range = req.getHeader(HEADER_CONTENT_RANGE);
+ if (range == null)
+ {
+ range = req.getHeader(HEADER_RANGE);
+ }
+ if (range != null)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Found content range header: " + range);
+
+ // ensure the range header is starts with "bytes=" and process the range(s)
+ if (range.length() > 6)
+ {
+ HttpRangeProcessor rangeProcessor = new HttpRangeProcessor(contentService);
+ processedRange = rangeProcessor.processRange(
+ res, reader, range.substring(6), nodeRef, propertyQName,
+ mimetype, req.getHeader(HEADER_USER_AGENT));
+ }
+ }
+ if (processedRange == false)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Sending complete file content...");
+
+ // set mimetype for the content and the character encoding for the stream
+ res.setContentType(mimetype);
+ res.setCharacterEncoding(reader.getEncoding());
+
+ // MNT-10642 Alfresco Explorer has javascript vulnerability opening HTML files
+ if (req.getRequestURI().contains("/d/d/") && (mimetype.equals("text/html") || mimetype.equals("application/xhtml+xml") || mimetype.equals("text/xml")))
+ {
+ String content = reader.getContentString();
+
+ if (mimetype.equals("text/html") || mimetype.equals("application/xhtml+xml"))
+ {
+ // process with HTML stripper
+ content = StringUtils.stripUnsafeHTMLTags(content, false);
+ }
+ else if (mimetype.equals("text/xml") && mimetype.equals("text/x-component"))
+ {
+ // IE supports "behaviour" which means that css can load a .htc file that could
+ // contain XSS code in the form of jscript, vbscript etc, to stop it form being
+ // evaluated we set the contient type to text/plain
+ res.setContentType("text/plain");
+ }
+
+ String encoding = reader.getEncoding();
+ byte[] bytes = encoding != null ? content.getBytes(encoding) : content.getBytes();
+ res.setContentLength(bytes.length);
+ res.getOutputStream().write(bytes);
+
+ return;
+ }
+
+ // return the complete entity range
+ long size = reader.getSize();
+ res.setHeader(HEADER_CONTENT_RANGE, "bytes 0-" + Long.toString(size-1L) + "/" + Long.toString(size));
+ res.setHeader(HEADER_CONTENT_LENGTH, Long.toString(size));
+ reader.getContent( res.getOutputStream() );
+ }
+ }
+ catch (SocketException e1)
+ {
+ // the client cut the connection - our mission was accomplished apart from a little error message
+ if (logger.isDebugEnabled())
+ logger.debug("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
+ }
+ catch (ContentIOException e2)
+ {
+ if (logger.isInfoEnabled())
+ logger.info("Failed stream read:\n\tnode: " + nodeRef + " due to: " + e2.getMessage());
+ }
+ catch (Throwable err)
+ {
+ if (err.getCause() instanceof SocketException)
+ {
+ // the client cut the connection - our mission was accomplished apart from a little error message
+ if (logger.isDebugEnabled())
+ logger.debug("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
+ }
+ else throw err;
+ }
+ }
+ else
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("HEAD request processed - no content sent.");
+ res.getOutputStream().close();
+ }
+ }
+ catch (Throwable err)
+ {
+ throw new AlfrescoRuntimeException("Error during download content servlet processing: " + err.getMessage(), err);
+ }
+ }
+
+ private void setHeaderContentDisposition(HttpServletRequest req, HttpServletResponse res, String filename)
+ {
+ // set header based on filename - will force a Save As from the browse if it doesn't recognise it
+ // this is better than the default response of the browser trying to display the contents
+
+ // IE requires that "Content-Disposition" header in case of "attachment" type should include
+ // "filename" part. See MNT-9900
+ String userAgent = req.getHeader(HEADER_USER_AGENT);
+ if (userAgent != null && (userAgent.toLowerCase().contains("firefox") || userAgent.toLowerCase().contains("safari")))
+ {
+ res.setHeader(HEADER_CONTENT_DISPOSITION, "attachment; filename=\"" + URLDecoder.decode(filename) + "\"");
+ }
+ else
+ {
+ res.setHeader(HEADER_CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"");
+ }
+
+ }
+
+ /**
+ * Helper to generate a URL to a content node for downloading content from the server.
+ *
+ * @param pattern The pattern to use for the URL
+ * @param ref NodeRef of the content node to generate URL for (cannot be null)
+ * @param name File name to return in the URL (cannot be null)
+ *
+ * @return URL to download the content from the specified node
+ */
+ protected final static String generateUrl(String pattern, NodeRef ref, String name)
+ {
+ return MessageFormat.format(pattern, new Object[] {
+ ref.getStoreRef().getProtocol(),
+ ref.getStoreRef().getIdentifier(),
+ ref.getId(),
+ URLEncoder.encode(name) } );
+ }
+}
diff --git a/source/java/org/alfresco/web/app/servlet/BaseServlet.java b/source/java/org/alfresco/web/app/servlet/BaseServlet.java
index b27587bc7a..e2a693d08e 100644
--- a/source/java/org/alfresco/web/app/servlet/BaseServlet.java
+++ b/source/java/org/alfresco/web/app/servlet/BaseServlet.java
@@ -1,481 +1,481 @@
-package org.alfresco.web.app.servlet;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.StringTokenizer;
-
-import javax.faces.context.FacesContext;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.alfresco.repo.security.authentication.AuthenticationUtil;
-import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
-import org.alfresco.repo.tenant.TenantService;
-import org.alfresco.service.ServiceRegistry;
-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.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.search.SearchService;
-import org.alfresco.service.cmr.security.AccessStatus;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.service.namespace.NamespaceService;
-import org.alfresco.web.app.Application;
-import org.alfresco.web.bean.LoginOutcomeBean;
-import org.alfresco.web.bean.repository.Repository;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.extensions.surf.util.URLDecoder;
-import org.springframework.web.context.WebApplicationContext;
-import org.springframework.web.context.support.WebApplicationContextUtils;
-import org.springframework.web.jsf.FacesContextUtils;
-
-
-/**
- * Base servlet class containing useful constant values and common methods for Alfresco servlets.
- *
- * @author Kevin Roast
- */
-public abstract class BaseServlet extends HttpServlet
-{
- private static final long serialVersionUID = -826295358696861789L;
-
- public static final String FACES_SERVLET = "/faces";
- public static final String KEY_STORE = "store";
- public static final String KEY_ROOT_PATH = "rootPath";
-
- /** an existing Ticket can be passed to most servlet for non-session based authentication */
- private static final String ARG_TICKET = "ticket";
-
- /** forcing guess access is available on most servlets */
- private static final String ARG_GUEST = "guest";
-
- private static final String MSG_ERROR_PERMISSIONS = "error_permissions";
-
- /** list of valid JSPs for redirect after a clean login */
- // TODO: make this list configurable
- private static Set validRedirectJSPs = new HashSet();
- static
- {
- validRedirectJSPs.add("/jsp/browse/browse.jsp");
- validRedirectJSPs.add("/jsp/admin/admin-console.jsp");
- validRedirectJSPs.add("/jsp/admin/avm-console.jsp");
- validRedirectJSPs.add("/jsp/admin/node-browser.jsp");
- validRedirectJSPs.add("/jsp/admin/store-browser.jsp");
- validRedirectJSPs.add("/jsp/users/user-console.jsp");
- validRedirectJSPs.add("/jsp/categories/categories.jsp");
- validRedirectJSPs.add("/jsp/dialog/about.jsp");
- validRedirectJSPs.add("/jsp/search/advanced-search.jsp");
- validRedirectJSPs.add("/jsp/admin/system-info.jsp");
- validRedirectJSPs.add("/jsp/forums/forums.jsp");
- validRedirectJSPs.add("/jsp/users/users.jsp");
- validRedirectJSPs.add("/jsp/trashcan/trash-list.jsp");
- }
-
- private static Log logger = LogFactory.getLog(BaseServlet.class);
-
-
- /**
- * Return the ServiceRegistry helper instance
- *
- * @param sc ServletContext
- *
- * @return ServiceRegistry
- */
- public static ServiceRegistry getServiceRegistry(ServletContext sc)
- {
- WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
- return (ServiceRegistry)wc.getBean(ServiceRegistry.SERVICE_REGISTRY);
- }
-
- /**
- * Perform an authentication for the servlet request URI. Processing any "ticket" or
- * "guest" URL arguments.
- *
- * @return AuthenticationStatus
- *
- * @throws IOException
- */
- public AuthenticationStatus servletAuthenticate(HttpServletRequest req, HttpServletResponse res)
- throws IOException
- {
- return servletAuthenticate(req, res, true);
- }
-
- /**
- * Perform an authentication for the servlet request URI. Processing any "ticket" or
- * "guest" URL arguments.
- *
- * @return AuthenticationStatus
- *
- * @throws IOException
- */
- public AuthenticationStatus servletAuthenticate(HttpServletRequest req, HttpServletResponse res,
- boolean redirectToLoginPage) throws IOException
- {
- AuthenticationStatus status;
-
- // see if a ticket or a force Guest parameter has been supplied
- String ticket = req.getParameter(ARG_TICKET);
- if (ticket != null && ticket.length() != 0)
- {
- status = AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
- }
- else
- {
- boolean forceGuest = false;
- String guest = req.getParameter(ARG_GUEST);
- if (guest != null)
- {
- forceGuest = Boolean.parseBoolean(guest);
- }
- status = AuthenticationHelper.authenticate(getServletContext(), req, res, forceGuest);
- }
- if (status == AuthenticationStatus.Failure && redirectToLoginPage)
- {
- // authentication failed - now need to display the login page to the user, if asked to
- redirectToLoginPage(req, res, getServletContext());
- }
-
- return status;
- }
-
- /**
- * Check the user has the given permission on the given node. If they do not either force a log on if this is a guest
- * user or forward to an error page.
- *
- * @param req
- * the request
- * @param res
- * the response
- * @param nodeRef
- * the node in question
- * @param allowLogIn
- * Indicates whether guest users without access to the node should be redirected to the log in page. If
- * false, a status 403 forbidden page is displayed instead.
- * @return true, if the user has access
- * @throws IOException
- * Signals that an I/O exception has occurred.
- * @throws ServletException
- * On other errors
- */
- public boolean checkAccess(HttpServletRequest req, HttpServletResponse res, NodeRef nodeRef, String permission,
- boolean allowLogIn) throws IOException, ServletException
- {
- ServletContext sc = getServletContext();
- ServiceRegistry serviceRegistry = getServiceRegistry(sc);
- PermissionService permissionService = serviceRegistry.getPermissionService();
-
- // check that the user has the permission
- if (permissionService.hasPermission(nodeRef, permission) == AccessStatus.DENIED)
- {
- if (logger.isDebugEnabled())
- logger.debug("User does not have " + permission + " permission for NodeRef: " + nodeRef.toString());
-
- if (allowLogIn && serviceRegistry.getAuthorityService().hasGuestAuthority())
- {
- if (logger.isDebugEnabled())
- logger.debug("Redirecting to login page...");
- redirectToLoginPage(req, res, sc);
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("Forwarding to error page...");
- Application
- .handleSystemError(sc, req, res, MSG_ERROR_PERMISSIONS, HttpServletResponse.SC_FORBIDDEN, logger);
- }
- return false;
- }
- return true;
- }
-
- /**
- * Redirect to the Login page - saving the current URL which can be redirected back later
- * once the user has successfully completed the authentication process.
- */
- public static void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res, ServletContext sc)
- throws IOException
- {
- redirectToLoginPage(req, res, sc, AuthenticationHelper.getRemoteUserMapper(sc) == null);
- }
-
- /**
- * Redirect to the Login page - saving the current URL which can be redirected back later
- * once the user has successfully completed the authentication process.
- * @param sendRedirect allow a redirect status code to be set? If false redirect
- * will be via markup rather than status code (to allow the status code to be used for handshake
- * responses etc.
- */
- public static void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res, ServletContext sc, boolean sendRedirect)
- throws IOException
- {
- // Pass the full requested URL as a parameter so the login page knows where to redirect to later
- final String uri = req.getRequestURI();
- String redirectURL = uri;
-
- // authentication failed - so end servlet execution and redirect to login page
- if (WebApplicationContextUtils.getRequiredWebApplicationContext(sc).containsBean(Application.BEAN_CONFIG_SERVICE))
- {
- StringBuilder redirect = new StringBuilder(128)
- .append(req.getContextPath()).append(FACES_SERVLET).append(Application.getLoginPage(sc));
-
- // if we find a JSF servlet reference in the URI then we need to check if the rest of the
- // JSP specified is valid for a redirect operation after Login has occured.
- int jspIndex;
- if (uri.indexOf(req.getContextPath() + FACES_SERVLET) == -1
- || uri.length() > (jspIndex = uri.indexOf(BaseServlet.FACES_SERVLET) + BaseServlet.FACES_SERVLET.length())
- && BaseServlet.validRedirectJSP(uri.substring(jspIndex)))
- {
- if (redirect.indexOf("?") == -1)
- {
- redirect.append('?');
- }
- else
- {
- redirect.append('&');
- }
- redirect.append(LoginOutcomeBean.PARAM_REDIRECT_URL);
- redirect.append('=');
- String url = uri;
-
- // Append the query string if necessary
- String queryString = req.getQueryString();
- if (queryString != null)
- {
- // Strip out leading ticket arguments
- queryString = queryString.replaceAll("(?<=^|&)" + ARG_TICKET + "(=[^&=]*)?&", "");
- // Strip out trailing ticket arguments
- queryString = queryString.replaceAll("(^|&)" + ARG_TICKET + "(=[^&=]*)?(?=&|$)", "");
- if (queryString.length() != 0)
- {
- url += "?" + queryString;
- }
- }
- redirect.append(URLEncoder.encode(url, "UTF-8"));
- }
- redirectURL = redirect.toString();
- }
- // If external authentication isn't in use (e.g. proxied share authentication), it's safe to return a redirect to the client
- if (sendRedirect)
- {
- res.sendRedirect(redirectURL);
- }
- // Otherwise, we must signal to the client with an unauthorized status code and rely on a browser refresh to do
- // the redirect for failover login (as we do with NTLM, Kerberos)
- else
- {
- res.setContentType("text/html; charset=UTF-8");
- res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-
- final PrintWriter out = res.getWriter();
- out.println("");
- out.println("");
- out.println("
");
- out.println("");
- out.close();
- }
- }
-
- /**
- * Apply the headers required to disallow caching of the response in the browser
- */
- public static void setNoCacheHeaders(HttpServletResponse res)
- {
- res.setHeader("Cache-Control", "no-cache");
- res.setHeader("Pragma", "no-cache");
- }
-
- /**
- * Returns true if the specified JSP file is valid for a redirect after login.
- * Only a specific sub-set of the available JSPs are valid to jump directly too after a
- * clean login attempt - e.g. those that do not require JSF bean context setup. This is
- * a limitation of the JSP architecture. The ExternalAccessServlet provides a mechanism to
- * setup the JSF bean context directly for some specific cases.
- *
- * @param jsp Filename of JSP to check, for example "/jsp/browse/browse.jsp"
- *
- * @return true if the JSP is in the list of valid direct URLs, false otherwise
- */
- public static boolean validRedirectJSP(String jsp)
- {
- return validRedirectJSPs.contains(jsp);
- }
-
- /**
- * Resolves the given path elements to a NodeRef in the current repository
- *
- * @param context Faces context
- * @param args The elements of the path to lookup
- */
- public static NodeRef resolveWebDAVPath(FacesContext context, String[] args)
- {
- WebApplicationContext wc = FacesContextUtils.getRequiredWebApplicationContext(context);
- return resolveWebDAVPath(wc, args, true);
- }
-
- /**
- * Resolves the given path elements to a NodeRef in the current repository
- *
- * @param context Faces context
- * @param args The elements of the path to lookup
- * @param decode True to decode the arg from UTF-8 format, false for no decoding
- */
- public static NodeRef resolveWebDAVPath(FacesContext context, String[] args, boolean decode)
- {
- WebApplicationContext wc = FacesContextUtils.getRequiredWebApplicationContext(context);
- return resolveWebDAVPath(wc, args, decode);
- }
-
- /**
- * Resolves the given path elements to a NodeRef in the current repository
- *
- * @param context ServletContext context
- * @param args The elements of the path to lookup
- */
- public static NodeRef resolveWebDAVPath(ServletContext context, String[] args)
- {
- WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
- return resolveWebDAVPath(wc, args, true);
- }
-
- /**
- * Resolves the given path elements to a NodeRef in the current repository
- *
- * @param context ServletContext context
- * @param args The elements of the path to lookup
- * @param decode True to decode the arg from UTF-8 format, false for no decoding
- */
- public static NodeRef resolveWebDAVPath(ServletContext context, String[] args, boolean decode)
- {
- WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
- return resolveWebDAVPath(wc, args, decode);
- }
-
- /**
- * Resolves the given path elements to a NodeRef in the current repository
- *
- * @param wc WebApplicationContext Context
- * @param args The elements of the path to lookup
- * @param decode True to decode the arg from UTF-8 format, false for no decoding
- */
- private static NodeRef resolveWebDAVPath(final WebApplicationContext wc, final String[] args, final boolean decode)
- {
- return AuthenticationUtil.runAs(new RunAsWork()
- {
- public NodeRef doWork() throws Exception
- {
- NodeRef nodeRef = null;
-
- List paths = new ArrayList(args.length - 1);
-
- FileInfo file = null;
- try
- {
- // create a list of path elements (decode the URL as we go)
- for (int x = 1; x < args.length; x++)
- {
- paths.add(decode ? URLDecoder.decode(args[x]) : args[x]);
- }
-
- if (logger.isDebugEnabled())
- logger.debug("Attempting to resolve webdav path: " + paths);
-
- // get the company home node to start the search from
- nodeRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
-
- TenantService tenantService = (TenantService)wc.getBean("tenantService");
- if (tenantService != null && tenantService.isEnabled())
- {
- if (logger.isDebugEnabled())
- logger.debug("MT is enabled.");
-
- NodeService nodeService = (NodeService) wc.getBean("NodeService");
- SearchService searchService = (SearchService) wc.getBean("SearchService");
- NamespaceService namespaceService = (NamespaceService) wc.getBean("NamespaceService");
-
- // TODO: since these constants are used more widely than just the WebDAVServlet,
- // they should be defined somewhere other than in that servlet
- String rootPath = wc.getServletContext().getInitParameter(BaseServlet.KEY_ROOT_PATH);
-
- // note: rootNodeRef is required (for storeRef part)
- nodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, nodeRef);
- }
-
- if (paths.size() != 0)
- {
- FileFolderService ffs = (FileFolderService)wc.getBean("FileFolderService");
- file = ffs.resolveNamePath(nodeRef, paths);
- nodeRef = file.getNodeRef();
- }
-
- if (logger.isDebugEnabled())
- logger.debug("Resolved webdav path to NodeRef: " + nodeRef);
- }
- catch (FileNotFoundException fne)
- {
- if (logger.isWarnEnabled())
- logger.warn("Failed to resolve webdav path", fne);
-
- nodeRef = null;
- }
- return nodeRef;
- }
- }, AuthenticationUtil.getSystemUserName());
- }
-
- /**
- * Resolve a name based into a NodeRef and Filename string
- *
- * @param sc ServletContext
- * @param path 'cm:name' based path using the '/' character as a separator
- *
- * @return PathRefInfo structure containing the resolved NodeRef and filename
- *
- * @throws IllegalArgumentException
- */
- public final static PathRefInfo resolveNamePath(ServletContext sc, String path)
- {
- StringTokenizer t = new StringTokenizer(path, "/");
- int tokenCount = t.countTokens();
- String[] elements = new String[tokenCount];
- for (int i=0; i validRedirectJSPs = new HashSet();
+ static
+ {
+ validRedirectJSPs.add("/jsp/browse/browse.jsp");
+ validRedirectJSPs.add("/jsp/admin/admin-console.jsp");
+ validRedirectJSPs.add("/jsp/admin/avm-console.jsp");
+ validRedirectJSPs.add("/jsp/admin/node-browser.jsp");
+ validRedirectJSPs.add("/jsp/admin/store-browser.jsp");
+ validRedirectJSPs.add("/jsp/users/user-console.jsp");
+ validRedirectJSPs.add("/jsp/categories/categories.jsp");
+ validRedirectJSPs.add("/jsp/dialog/about.jsp");
+ validRedirectJSPs.add("/jsp/search/advanced-search.jsp");
+ validRedirectJSPs.add("/jsp/admin/system-info.jsp");
+ validRedirectJSPs.add("/jsp/forums/forums.jsp");
+ validRedirectJSPs.add("/jsp/users/users.jsp");
+ validRedirectJSPs.add("/jsp/trashcan/trash-list.jsp");
+ }
+
+ private static Log logger = LogFactory.getLog(BaseServlet.class);
+
+
+ /**
+ * Return the ServiceRegistry helper instance
+ *
+ * @param sc ServletContext
+ *
+ * @return ServiceRegistry
+ */
+ public static ServiceRegistry getServiceRegistry(ServletContext sc)
+ {
+ WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
+ return (ServiceRegistry)wc.getBean(ServiceRegistry.SERVICE_REGISTRY);
+ }
+
+ /**
+ * Perform an authentication for the servlet request URI. Processing any "ticket" or
+ * "guest" URL arguments.
+ *
+ * @return AuthenticationStatus
+ *
+ * @throws IOException
+ */
+ public AuthenticationStatus servletAuthenticate(HttpServletRequest req, HttpServletResponse res)
+ throws IOException
+ {
+ return servletAuthenticate(req, res, true);
+ }
+
+ /**
+ * Perform an authentication for the servlet request URI. Processing any "ticket" or
+ * "guest" URL arguments.
+ *
+ * @return AuthenticationStatus
+ *
+ * @throws IOException
+ */
+ public AuthenticationStatus servletAuthenticate(HttpServletRequest req, HttpServletResponse res,
+ boolean redirectToLoginPage) throws IOException
+ {
+ AuthenticationStatus status;
+
+ // see if a ticket or a force Guest parameter has been supplied
+ String ticket = req.getParameter(ARG_TICKET);
+ if (ticket != null && ticket.length() != 0)
+ {
+ status = AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
+ }
+ else
+ {
+ boolean forceGuest = false;
+ String guest = req.getParameter(ARG_GUEST);
+ if (guest != null)
+ {
+ forceGuest = Boolean.parseBoolean(guest);
+ }
+ status = AuthenticationHelper.authenticate(getServletContext(), req, res, forceGuest);
+ }
+ if (status == AuthenticationStatus.Failure && redirectToLoginPage)
+ {
+ // authentication failed - now need to display the login page to the user, if asked to
+ redirectToLoginPage(req, res, getServletContext());
+ }
+
+ return status;
+ }
+
+ /**
+ * Check the user has the given permission on the given node. If they do not either force a log on if this is a guest
+ * user or forward to an error page.
+ *
+ * @param req
+ * the request
+ * @param res
+ * the response
+ * @param nodeRef
+ * the node in question
+ * @param allowLogIn
+ * Indicates whether guest users without access to the node should be redirected to the log in page. If
+ * false, a status 403 forbidden page is displayed instead.
+ * @return true, if the user has access
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ * @throws ServletException
+ * On other errors
+ */
+ public boolean checkAccess(HttpServletRequest req, HttpServletResponse res, NodeRef nodeRef, String permission,
+ boolean allowLogIn) throws IOException, ServletException
+ {
+ ServletContext sc = getServletContext();
+ ServiceRegistry serviceRegistry = getServiceRegistry(sc);
+ PermissionService permissionService = serviceRegistry.getPermissionService();
+
+ // check that the user has the permission
+ if (permissionService.hasPermission(nodeRef, permission) == AccessStatus.DENIED)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("User does not have " + permission + " permission for NodeRef: " + nodeRef.toString());
+
+ if (allowLogIn && serviceRegistry.getAuthorityService().hasGuestAuthority())
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Redirecting to login page...");
+ redirectToLoginPage(req, res, sc);
+ }
+ else
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Forwarding to error page...");
+ Application
+ .handleSystemError(sc, req, res, MSG_ERROR_PERMISSIONS, HttpServletResponse.SC_FORBIDDEN, logger);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Redirect to the Login page - saving the current URL which can be redirected back later
+ * once the user has successfully completed the authentication process.
+ */
+ public static void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res, ServletContext sc)
+ throws IOException
+ {
+ redirectToLoginPage(req, res, sc, AuthenticationHelper.getRemoteUserMapper(sc) == null);
+ }
+
+ /**
+ * Redirect to the Login page - saving the current URL which can be redirected back later
+ * once the user has successfully completed the authentication process.
+ * @param sendRedirect allow a redirect status code to be set? If false redirect
+ * will be via markup rather than status code (to allow the status code to be used for handshake
+ * responses etc.
+ */
+ public static void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res, ServletContext sc, boolean sendRedirect)
+ throws IOException
+ {
+ // Pass the full requested URL as a parameter so the login page knows where to redirect to later
+ final String uri = req.getRequestURI();
+ String redirectURL = uri;
+
+ // authentication failed - so end servlet execution and redirect to login page
+ if (WebApplicationContextUtils.getRequiredWebApplicationContext(sc).containsBean(Application.BEAN_CONFIG_SERVICE))
+ {
+ StringBuilder redirect = new StringBuilder(128)
+ .append(req.getContextPath()).append(FACES_SERVLET).append(Application.getLoginPage(sc));
+
+ // if we find a JSF servlet reference in the URI then we need to check if the rest of the
+ // JSP specified is valid for a redirect operation after Login has occured.
+ int jspIndex;
+ if (uri.indexOf(req.getContextPath() + FACES_SERVLET) == -1
+ || uri.length() > (jspIndex = uri.indexOf(BaseServlet.FACES_SERVLET) + BaseServlet.FACES_SERVLET.length())
+ && BaseServlet.validRedirectJSP(uri.substring(jspIndex)))
+ {
+ if (redirect.indexOf("?") == -1)
+ {
+ redirect.append('?');
+ }
+ else
+ {
+ redirect.append('&');
+ }
+ redirect.append(LoginOutcomeBean.PARAM_REDIRECT_URL);
+ redirect.append('=');
+ String url = uri;
+
+ // Append the query string if necessary
+ String queryString = req.getQueryString();
+ if (queryString != null)
+ {
+ // Strip out leading ticket arguments
+ queryString = queryString.replaceAll("(?<=^|&)" + ARG_TICKET + "(=[^&=]*)?&", "");
+ // Strip out trailing ticket arguments
+ queryString = queryString.replaceAll("(^|&)" + ARG_TICKET + "(=[^&=]*)?(?=&|$)", "");
+ if (queryString.length() != 0)
+ {
+ url += "?" + queryString;
+ }
+ }
+ redirect.append(URLEncoder.encode(url, "UTF-8"));
+ }
+ redirectURL = redirect.toString();
+ }
+ // If external authentication isn't in use (e.g. proxied share authentication), it's safe to return a redirect to the client
+ if (sendRedirect)
+ {
+ res.sendRedirect(redirectURL);
+ }
+ // Otherwise, we must signal to the client with an unauthorized status code and rely on a browser refresh to do
+ // the redirect for failover login (as we do with NTLM, Kerberos)
+ else
+ {
+ res.setContentType("text/html; charset=UTF-8");
+ res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+
+ final PrintWriter out = res.getWriter();
+ out.println("");
+ out.println("");
+ out.println("
");
+ out.println("");
+ out.close();
+ }
+ }
+
+ /**
+ * Apply the headers required to disallow caching of the response in the browser
+ */
+ public static void setNoCacheHeaders(HttpServletResponse res)
+ {
+ res.setHeader("Cache-Control", "no-cache");
+ res.setHeader("Pragma", "no-cache");
+ }
+
+ /**
+ * Returns true if the specified JSP file is valid for a redirect after login.
+ * Only a specific sub-set of the available JSPs are valid to jump directly too after a
+ * clean login attempt - e.g. those that do not require JSF bean context setup. This is
+ * a limitation of the JSP architecture. The ExternalAccessServlet provides a mechanism to
+ * setup the JSF bean context directly for some specific cases.
+ *
+ * @param jsp Filename of JSP to check, for example "/jsp/browse/browse.jsp"
+ *
+ * @return true if the JSP is in the list of valid direct URLs, false otherwise
+ */
+ public static boolean validRedirectJSP(String jsp)
+ {
+ return validRedirectJSPs.contains(jsp);
+ }
+
+ /**
+ * Resolves the given path elements to a NodeRef in the current repository
+ *
+ * @param context Faces context
+ * @param args The elements of the path to lookup
+ */
+ public static NodeRef resolveWebDAVPath(FacesContext context, String[] args)
+ {
+ WebApplicationContext wc = FacesContextUtils.getRequiredWebApplicationContext(context);
+ return resolveWebDAVPath(wc, args, true);
+ }
+
+ /**
+ * Resolves the given path elements to a NodeRef in the current repository
+ *
+ * @param context Faces context
+ * @param args The elements of the path to lookup
+ * @param decode True to decode the arg from UTF-8 format, false for no decoding
+ */
+ public static NodeRef resolveWebDAVPath(FacesContext context, String[] args, boolean decode)
+ {
+ WebApplicationContext wc = FacesContextUtils.getRequiredWebApplicationContext(context);
+ return resolveWebDAVPath(wc, args, decode);
+ }
+
+ /**
+ * Resolves the given path elements to a NodeRef in the current repository
+ *
+ * @param context ServletContext context
+ * @param args The elements of the path to lookup
+ */
+ public static NodeRef resolveWebDAVPath(ServletContext context, String[] args)
+ {
+ WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
+ return resolveWebDAVPath(wc, args, true);
+ }
+
+ /**
+ * Resolves the given path elements to a NodeRef in the current repository
+ *
+ * @param context ServletContext context
+ * @param args The elements of the path to lookup
+ * @param decode True to decode the arg from UTF-8 format, false for no decoding
+ */
+ public static NodeRef resolveWebDAVPath(ServletContext context, String[] args, boolean decode)
+ {
+ WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
+ return resolveWebDAVPath(wc, args, decode);
+ }
+
+ /**
+ * Resolves the given path elements to a NodeRef in the current repository
+ *
+ * @param wc WebApplicationContext Context
+ * @param args The elements of the path to lookup
+ * @param decode True to decode the arg from UTF-8 format, false for no decoding
+ */
+ private static NodeRef resolveWebDAVPath(final WebApplicationContext wc, final String[] args, final boolean decode)
+ {
+ return AuthenticationUtil.runAs(new RunAsWork()
+ {
+ public NodeRef doWork() throws Exception
+ {
+ NodeRef nodeRef = null;
+
+ List paths = new ArrayList(args.length - 1);
+
+ FileInfo file = null;
+ try
+ {
+ // create a list of path elements (decode the URL as we go)
+ for (int x = 1; x < args.length; x++)
+ {
+ paths.add(decode ? URLDecoder.decode(args[x]) : args[x]);
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Attempting to resolve webdav path: " + paths);
+
+ // get the company home node to start the search from
+ nodeRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
+
+ TenantService tenantService = (TenantService)wc.getBean("tenantService");
+ if (tenantService != null && tenantService.isEnabled())
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("MT is enabled.");
+
+ NodeService nodeService = (NodeService) wc.getBean("NodeService");
+ SearchService searchService = (SearchService) wc.getBean("SearchService");
+ NamespaceService namespaceService = (NamespaceService) wc.getBean("NamespaceService");
+
+ // TODO: since these constants are used more widely than just the WebDAVServlet,
+ // they should be defined somewhere other than in that servlet
+ String rootPath = wc.getServletContext().getInitParameter(BaseServlet.KEY_ROOT_PATH);
+
+ // note: rootNodeRef is required (for storeRef part)
+ nodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, nodeRef);
+ }
+
+ if (paths.size() != 0)
+ {
+ FileFolderService ffs = (FileFolderService)wc.getBean("FileFolderService");
+ file = ffs.resolveNamePath(nodeRef, paths);
+ nodeRef = file.getNodeRef();
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Resolved webdav path to NodeRef: " + nodeRef);
+ }
+ catch (FileNotFoundException fne)
+ {
+ if (logger.isWarnEnabled())
+ logger.warn("Failed to resolve webdav path", fne);
+
+ nodeRef = null;
+ }
+ return nodeRef;
+ }
+ }, AuthenticationUtil.getSystemUserName());
+ }
+
+ /**
+ * Resolve a name based into a NodeRef and Filename string
+ *
+ * @param sc ServletContext
+ * @param path 'cm:name' based path using the '/' character as a separator
+ *
+ * @return PathRefInfo structure containing the resolved NodeRef and filename
+ *
+ * @throws IllegalArgumentException
+ */
+ public final static PathRefInfo resolveNamePath(ServletContext sc, String path)
+ {
+ StringTokenizer t = new StringTokenizer(path, "/");
+ int tokenCount = t.countTokens();
+ String[] elements = new String[tokenCount];
+ for (int i=0; i
- * This will show all debug entries from this class as though they
- * came from the subclass.
- *
- * @return The logger
- */
- protected abstract Log getLogger();
-
- /**
- * Builds the FreeMarker model
- *
- * @param services Service Registry instance
- * @param req Http request
- * @param templateRef The node ref of the template to process
- * @return The FreeMarker model
- */
- protected abstract Map buildModel(ServiceRegistry services,
- HttpServletRequest req, NodeRef templateRef);
-
- /**
- * Processes the template request using the current context i.e. no
- * authentication checks are made, it is presumed they have already
- * been done.
- *
- * @param req The HTTP request
- * @param res The HTTP response
- * @param redirectToLogin Flag to determine whether to redirect to the login
- * page if the user does not have the correct permissions
- */
- protected void processTemplateRequest(HttpServletRequest req, HttpServletResponse res,
- boolean redirectToLogin) throws ServletException, IOException
- {
- Log logger = getLogger();
- String uri = req.getRequestURI();
-
- if (logger.isDebugEnabled())
- {
- String queryString = req.getQueryString();
- logger.debug("Processing URL: " + uri +
- ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
- }
-
- uri = uri.substring(req.getContextPath().length());
- StringTokenizer t = new StringTokenizer(uri, "/");
- int tokenCount = t.countTokens();
-
- t.nextToken(); // skip servlet name
-
- NodeRef nodeRef = null;
- NodeRef templateRef = null;
-
- try
- {
- String contentPath = req.getParameter(ARG_CONTEXT_PATH);
- if (contentPath != null && contentPath.length() != 0)
- {
- // process the name based path to resolve the NodeRef
- PathRefInfo pathInfo = resolveNamePath(getServletContext(), contentPath);
-
- nodeRef = pathInfo.NodeRef;
- }
- else if (tokenCount > 3)
- {
- // get NodeRef to the content from the URL elements
- StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
- nodeRef = new NodeRef(storeRef, t.nextToken());
- }
-
- // get NodeRef to the template if supplied
- String templatePath = req.getParameter(ARG_TEMPLATE_PATH);
- if (templatePath != null && templatePath.length() != 0)
- {
- // process the name based path to resolve the NodeRef
- PathRefInfo pathInfo = resolveNamePath(getServletContext(), templatePath);
-
- templateRef = pathInfo.NodeRef;
- }
- else if (tokenCount >= 7)
- {
- StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
- templateRef = new NodeRef(storeRef, t.nextToken());
- }
- }
- catch (AccessDeniedException err)
- {
- if (redirectToLogin)
- {
- if (logger.isDebugEnabled())
- logger.debug("Redirecting to login page...");
-
- redirectToLoginPage(req, res, getServletContext());
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("Returning 403 Forbidden error...");
-
- res.sendError(HttpServletResponse.SC_FORBIDDEN);
- }
-
- return;
- }
-
- // if no context is specified, use the template itself
- // TODO: should this default to something else?
- if (nodeRef == null && templateRef != null)
- {
- nodeRef = templateRef;
- }
-
- if (nodeRef == null)
- {
- throw new TemplateException("Not enough elements supplied in URL or no 'path' argument specified.");
- }
-
- // get the services we need to retrieve the content
- ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
- NodeService nodeService = serviceRegistry.getNodeService();
- TemplateService templateService = serviceRegistry.getTemplateService();
- PermissionService permissionService = serviceRegistry.getPermissionService();
-
- // check that the user has at least READ access on any nodes - else redirect to the login page
- if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED ||
- (templateRef != null && permissionService.hasPermission(templateRef, PermissionService.READ) == AccessStatus.DENIED))
- {
- if (redirectToLogin)
- {
- if (logger.isDebugEnabled())
- logger.debug("Redirecting to login page...");
-
- redirectToLoginPage(req, res, getServletContext());
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("Returning 403 Forbidden error...");
-
- res.sendError(HttpServletResponse.SC_FORBIDDEN);
- }
-
- return;
- }
-
- String mimetype = MIMETYPE_HTML;
- if (req.getParameter(ARG_MIMETYPE) != null)
- {
- mimetype = req.getParameter(ARG_MIMETYPE);
- }
- res.setContentType(mimetype);
-
- try
- {
- UserTransaction txn = null;
- try
- {
- txn = serviceRegistry.getTransactionService().getUserTransaction(true);
- txn.begin();
-
- // if template not supplied, then use the default against the node
- if (templateRef == null)
- {
- if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPLATABLE))
- {
- templateRef = (NodeRef)nodeService.getProperty(nodeRef, ContentModel.PROP_TEMPLATE);
- }
- if (templateRef == null)
- {
- throw new TemplateException("Template reference not set against node or not supplied in URL.");
- }
- }
-
- // create the model - put the supplied noderef in as space/document as appropriate
- Map model = getModel(serviceRegistry, req, templateRef, nodeRef);
-
- // process the template against the node content directly to the response output stream
- // assuming the repo is capable of streaming in chunks, this should allow large files
- // to be streamed directly to the browser response stream.
- try
- {
- templateService.processTemplate(
- templateRef.toString(),
- model,
- res.getWriter());
-
- // commit the transaction
- txn.commit();
- }
- catch (SocketException e)
- {
- if (e.getMessage().contains("ClientAbortException"))
- {
- // the client cut the connection - our mission was accomplished apart from a little error message
- logger.error("Client aborted stream read:\n node: " + nodeRef + "\n template: " + templateRef);
- try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
- }
- else
- {
- throw e;
- }
- }
- finally
- {
- res.getWriter().close();
- }
- }
- catch (Throwable txnErr)
- {
- try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
- throw txnErr;
- }
- }
- catch (Throwable err)
- {
- throw new AlfrescoRuntimeException("Error during template servlet processing: " + err.getMessage(), err);
- }
- }
-
- /**
- * Build the model that to process the template against.
- *
- * The model includes the usual template root objects such as 'companyhome', 'userhome',
- * 'person' and also includes the node specified on the servlet URL as 'space' and 'document'
- *
- * @param services ServiceRegistry
- * @param req Http request - for accessing Session and url args
- * @param templateRef NodeRef of the template itself
- * @param nodeRef NodeRef of the space/document to process template against
- *
- * @return an object model ready for executing template against
- */
- @SuppressWarnings("unchecked")
- private Map getModel(ServiceRegistry services, HttpServletRequest req, NodeRef templateRef, NodeRef nodeRef)
- {
- // build FreeMarker default model and merge
- Map root = buildModel(services, req, templateRef);
-
- // put the current NodeRef in as "space" and "document"
- root.put("space", nodeRef);
- root.put("document", nodeRef);
-
- // add URL arguments as a map called 'args' to the root of the model
- Map args = new HashMap(8, 1.0f);
- Enumeration names = req.getParameterNames();
- while (names.hasMoreElements())
- {
- String name = (String)names.nextElement();
- try
- {
- args.put(name, new String(req.getParameter(name).getBytes(), "UTF-8"));
- }
- catch (UnsupportedEncodingException err) {}
- }
- root.put("args", args);
-
- // Add the image resolver
- root.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver);
-
- // method to allow client urls to be generated
- root.put("url", new URLHelper(req));
-
- return root;
- }
-
- /** Template Image resolver helper */
- protected TemplateImageResolver imageResolver = new TemplateImageResolver()
- {
- public String resolveImagePathForName(String filename, FileTypeImageSize size)
- {
- return FileTypeImageUtils.getFileTypeImage(getServletContext(), filename, size);
- }
- };
-
- /**
- * Helper to return context path for generating urls
- */
- public static class URLHelper
- {
- String contextPath;
- String serverPath;
-
- public URLHelper(HttpServletRequest request)
- {
- this.contextPath = request.getContextPath();
- this.serverPath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
- }
-
- public URLHelper(FacesContext context)
- {
- this.contextPath = context.getExternalContext().getRequestContextPath();
- final Object request = context.getExternalContext().getRequest();
- if (request instanceof HttpServletRequest)
- {
- final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
- this.serverPath = httpServletRequest.getScheme() + "://" + httpServletRequest.getServerName() + ":" + httpServletRequest.getServerPort();
- }
- }
-
- public String getContext()
- {
- return this.contextPath;
- }
-
- public String getServerPath()
- {
- return this.serverPath;
- }
- }
-}
+package org.alfresco.web.app.servlet;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.SocketException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.faces.context.FacesContext;
+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.model.ContentModel;
+import org.alfresco.repo.security.permissions.AccessDeniedException;
+import org.alfresco.repo.web.scripts.FileTypeImageUtils;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.repository.FileTypeImageSize;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.StoreRef;
+import org.alfresco.service.cmr.repository.TemplateException;
+import org.alfresco.service.cmr.repository.TemplateImageResolver;
+import org.alfresco.service.cmr.repository.TemplateService;
+import org.alfresco.service.cmr.security.AccessStatus;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.apache.commons.logging.Log;
+
+/**
+ * Base class for the template content servlets. Provides common
+ * processing for the request.
+ *
+ * @see org.alfresco.web.app.servlet.TemplateContentServlet
+ * @see org.alfresco.web.app.servlet.GuestTemplateContentServlet
+ *
+ * @author Kevin Roast
+ * @author gavinc
+ */
+@SuppressWarnings("serial")
+public abstract class BaseTemplateContentServlet extends BaseServlet
+{
+ private static final String MIMETYPE_HTML = "text/html;charset=utf-8";
+
+ private static final long serialVersionUID = -4123407921997235977L;
+
+ private static final String ARG_MIMETYPE = "mimetype";
+ private static final String ARG_TEMPLATE_PATH = "templatePath";
+ private static final String ARG_CONTEXT_PATH = "contextPath";
+
+ /**
+ * Gets the logger to use for this request.
+ *
+ * This will show all debug entries from this class as though they
+ * came from the subclass.
+ *
+ * @return The logger
+ */
+ protected abstract Log getLogger();
+
+ /**
+ * Builds the FreeMarker model
+ *
+ * @param services Service Registry instance
+ * @param req Http request
+ * @param templateRef The node ref of the template to process
+ * @return The FreeMarker model
+ */
+ protected abstract Map buildModel(ServiceRegistry services,
+ HttpServletRequest req, NodeRef templateRef);
+
+ /**
+ * Processes the template request using the current context i.e. no
+ * authentication checks are made, it is presumed they have already
+ * been done.
+ *
+ * @param req The HTTP request
+ * @param res The HTTP response
+ * @param redirectToLogin Flag to determine whether to redirect to the login
+ * page if the user does not have the correct permissions
+ */
+ protected void processTemplateRequest(HttpServletRequest req, HttpServletResponse res,
+ boolean redirectToLogin) throws ServletException, IOException
+ {
+ Log logger = getLogger();
+ String uri = req.getRequestURI();
+
+ if (logger.isDebugEnabled())
+ {
+ String queryString = req.getQueryString();
+ logger.debug("Processing URL: " + uri +
+ ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
+ }
+
+ uri = uri.substring(req.getContextPath().length());
+ StringTokenizer t = new StringTokenizer(uri, "/");
+ int tokenCount = t.countTokens();
+
+ t.nextToken(); // skip servlet name
+
+ NodeRef nodeRef = null;
+ NodeRef templateRef = null;
+
+ try
+ {
+ String contentPath = req.getParameter(ARG_CONTEXT_PATH);
+ if (contentPath != null && contentPath.length() != 0)
+ {
+ // process the name based path to resolve the NodeRef
+ PathRefInfo pathInfo = resolveNamePath(getServletContext(), contentPath);
+
+ nodeRef = pathInfo.NodeRef;
+ }
+ else if (tokenCount > 3)
+ {
+ // get NodeRef to the content from the URL elements
+ StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
+ nodeRef = new NodeRef(storeRef, t.nextToken());
+ }
+
+ // get NodeRef to the template if supplied
+ String templatePath = req.getParameter(ARG_TEMPLATE_PATH);
+ if (templatePath != null && templatePath.length() != 0)
+ {
+ // process the name based path to resolve the NodeRef
+ PathRefInfo pathInfo = resolveNamePath(getServletContext(), templatePath);
+
+ templateRef = pathInfo.NodeRef;
+ }
+ else if (tokenCount >= 7)
+ {
+ StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
+ templateRef = new NodeRef(storeRef, t.nextToken());
+ }
+ }
+ catch (AccessDeniedException err)
+ {
+ if (redirectToLogin)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Redirecting to login page...");
+
+ redirectToLoginPage(req, res, getServletContext());
+ }
+ else
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Returning 403 Forbidden error...");
+
+ res.sendError(HttpServletResponse.SC_FORBIDDEN);
+ }
+
+ return;
+ }
+
+ // if no context is specified, use the template itself
+ // TODO: should this default to something else?
+ if (nodeRef == null && templateRef != null)
+ {
+ nodeRef = templateRef;
+ }
+
+ if (nodeRef == null)
+ {
+ throw new TemplateException("Not enough elements supplied in URL or no 'path' argument specified.");
+ }
+
+ // get the services we need to retrieve the content
+ ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
+ NodeService nodeService = serviceRegistry.getNodeService();
+ TemplateService templateService = serviceRegistry.getTemplateService();
+ PermissionService permissionService = serviceRegistry.getPermissionService();
+
+ // check that the user has at least READ access on any nodes - else redirect to the login page
+ if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED ||
+ (templateRef != null && permissionService.hasPermission(templateRef, PermissionService.READ) == AccessStatus.DENIED))
+ {
+ if (redirectToLogin)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Redirecting to login page...");
+
+ redirectToLoginPage(req, res, getServletContext());
+ }
+ else
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Returning 403 Forbidden error...");
+
+ res.sendError(HttpServletResponse.SC_FORBIDDEN);
+ }
+
+ return;
+ }
+
+ String mimetype = MIMETYPE_HTML;
+ if (req.getParameter(ARG_MIMETYPE) != null)
+ {
+ mimetype = req.getParameter(ARG_MIMETYPE);
+ }
+ res.setContentType(mimetype);
+
+ try
+ {
+ UserTransaction txn = null;
+ try
+ {
+ txn = serviceRegistry.getTransactionService().getUserTransaction(true);
+ txn.begin();
+
+ // if template not supplied, then use the default against the node
+ if (templateRef == null)
+ {
+ if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPLATABLE))
+ {
+ templateRef = (NodeRef)nodeService.getProperty(nodeRef, ContentModel.PROP_TEMPLATE);
+ }
+ if (templateRef == null)
+ {
+ throw new TemplateException("Template reference not set against node or not supplied in URL.");
+ }
+ }
+
+ // create the model - put the supplied noderef in as space/document as appropriate
+ Map model = getModel(serviceRegistry, req, templateRef, nodeRef);
+
+ // process the template against the node content directly to the response output stream
+ // assuming the repo is capable of streaming in chunks, this should allow large files
+ // to be streamed directly to the browser response stream.
+ try
+ {
+ templateService.processTemplate(
+ templateRef.toString(),
+ model,
+ res.getWriter());
+
+ // commit the transaction
+ txn.commit();
+ }
+ catch (SocketException e)
+ {
+ if (e.getMessage().contains("ClientAbortException"))
+ {
+ // the client cut the connection - our mission was accomplished apart from a little error message
+ logger.error("Client aborted stream read:\n node: " + nodeRef + "\n template: " + templateRef);
+ try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ finally
+ {
+ res.getWriter().close();
+ }
+ }
+ catch (Throwable txnErr)
+ {
+ try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
+ throw txnErr;
+ }
+ }
+ catch (Throwable err)
+ {
+ throw new AlfrescoRuntimeException("Error during template servlet processing: " + err.getMessage(), err);
+ }
+ }
+
+ /**
+ * Build the model that to process the template against.
+ *
+ * The model includes the usual template root objects such as 'companyhome', 'userhome',
+ * 'person' and also includes the node specified on the servlet URL as 'space' and 'document'
+ *
+ * @param services ServiceRegistry
+ * @param req Http request - for accessing Session and url args
+ * @param templateRef NodeRef of the template itself
+ * @param nodeRef NodeRef of the space/document to process template against
+ *
+ * @return an object model ready for executing template against
+ */
+ @SuppressWarnings("unchecked")
+ private Map getModel(ServiceRegistry services, HttpServletRequest req, NodeRef templateRef, NodeRef nodeRef)
+ {
+ // build FreeMarker default model and merge
+ Map root = buildModel(services, req, templateRef);
+
+ // put the current NodeRef in as "space" and "document"
+ root.put("space", nodeRef);
+ root.put("document", nodeRef);
+
+ // add URL arguments as a map called 'args' to the root of the model
+ Map args = new HashMap(8, 1.0f);
+ Enumeration names = req.getParameterNames();
+ while (names.hasMoreElements())
+ {
+ String name = (String)names.nextElement();
+ try
+ {
+ args.put(name, new String(req.getParameter(name).getBytes(), "UTF-8"));
+ }
+ catch (UnsupportedEncodingException err) {}
+ }
+ root.put("args", args);
+
+ // Add the image resolver
+ root.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver);
+
+ // method to allow client urls to be generated
+ root.put("url", new URLHelper(req));
+
+ return root;
+ }
+
+ /** Template Image resolver helper */
+ protected TemplateImageResolver imageResolver = new TemplateImageResolver()
+ {
+ public String resolveImagePathForName(String filename, FileTypeImageSize size)
+ {
+ return FileTypeImageUtils.getFileTypeImage(getServletContext(), filename, size);
+ }
+ };
+
+ /**
+ * Helper to return context path for generating urls
+ */
+ public static class URLHelper
+ {
+ String contextPath;
+ String serverPath;
+
+ public URLHelper(HttpServletRequest request)
+ {
+ this.contextPath = request.getContextPath();
+ this.serverPath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
+ }
+
+ public URLHelper(FacesContext context)
+ {
+ this.contextPath = context.getExternalContext().getRequestContextPath();
+ final Object request = context.getExternalContext().getRequest();
+ if (request instanceof HttpServletRequest)
+ {
+ final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+ this.serverPath = httpServletRequest.getScheme() + "://" + httpServletRequest.getServerName() + ":" + httpServletRequest.getServerPort();
+ }
+ }
+
+ public String getContext()
+ {
+ return this.contextPath;
+ }
+
+ public String getServerPath()
+ {
+ return this.serverPath;
+ }
+ }
+}
diff --git a/source/java/org/alfresco/web/app/servlet/CommandServlet.java b/source/java/org/alfresco/web/app/servlet/CommandServlet.java
index 41bc23ea2c..8c2fe89201 100644
--- a/source/java/org/alfresco/web/app/servlet/CommandServlet.java
+++ b/source/java/org/alfresco/web/app/servlet/CommandServlet.java
@@ -1,248 +1,248 @@
-package org.alfresco.web.app.servlet;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Enumeration;
-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.springframework.extensions.config.Config;
-import org.alfresco.error.AlfrescoRuntimeException;
-import org.alfresco.service.ServiceRegistry;
-import org.alfresco.web.app.Application;
-import org.alfresco.web.app.servlet.command.CommandFactory;
-import org.alfresco.web.app.servlet.command.CommandProcessor;
-import org.alfresco.web.app.servlet.command.ExtCommandProcessor;
-import org.alfresco.web.config.CommandServletConfigElement;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Servlet responsible for executing commands upon node(s).
- *
- * The URL to the servlet should be generated thus:
- *
- * The 'processor-name' identifies the command processor to execute the command. For example the
- * 'workflow' processor will execute workflow commands upon a node (e.g. "approve" or "reject").
- * For example:
- *
- * 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.
- *
- * A 'return-page' URL argument can be specified as the redirect page to navigate too after processing.
- *
- * Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
- * ?ticket=1234567890
- *
- * And/or also followed by the "?guest=true" argument to force guest access login for the URL.
- *
- * @author Kevin Roast
- * @deprecated 5.0 not exposed in web-client web.xml
- */
-public class CommandServlet extends BaseServlet
-{
- private static final long serialVersionUID = -5432407921038376133L;
-
- private static Log logger = LogFactory.getLog(CommandServlet.class);
-
- private static CommandFactory commandfactory = CommandFactory.getInstance();
-
- public static final String ARG_RETURNPAGE = "return-page";
-
- /**
- * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
- */
- protected void service(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;
- }
-
- setNoCacheHeaders(res);
-
- uri = uri.substring(req.getContextPath().length());
- StringTokenizer t = new StringTokenizer(uri, "/");
- int tokenCount = t.countTokens();
- if (tokenCount < 3)
- {
- throw new IllegalArgumentException("Command Servlet URL did not contain all required args: " + uri);
- }
-
- t.nextToken(); // skip servlet name
-
- // get the command processor to execute the command e.g. "workflow"
- String procName = t.nextToken();
-
- // get the command to perform
- String command = t.nextToken();
-
- // get any remaining uri elements to pass to the processor
- String[] urlElements = new String[tokenCount - 3];
- for (int i=0; i args = new HashMap(8, 1.0f);
- Enumeration names = req.getParameterNames();
- while (names.hasMoreElements())
- {
- String name = (String)names.nextElement();
- args.put(name, req.getParameter(name));
- }
-
- try
- {
- // get configured command processor by name from Config Service
- CommandProcessor processor = createCommandProcessor(procName);
-
- // validate that the processor has everything it needs to run the command
- if (processor.validateArguments(getServletContext(), command, args, urlElements) == false)
- {
- redirectToLoginPage(req, res, getServletContext());
- return;
- }
-
- ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
- UserTransaction txn = null;
- try
- {
- txn = serviceRegistry.getTransactionService().getUserTransaction();
- txn.begin();
-
- // inform the processor to execute the specified command
- if (processor instanceof ExtCommandProcessor)
- {
- ((ExtCommandProcessor)processor).process(serviceRegistry, req, res, command);
- }
- else
- {
- processor.process(serviceRegistry, req, command);
- }
-
- // commit the transaction
- txn.commit();
- }
- catch (Throwable txnErr)
- {
- try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
- throw txnErr;
- }
-
- String returnPage = req.getParameter(ARG_RETURNPAGE);
- if (returnPage != null && returnPage.length() != 0)
- {
- validateReturnPage(returnPage, req);
- 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.");
-
- if (res.getContentType() == null && !res.isCommitted())
- {
- res.setContentType("text/html");
-
- // request that the processor output a useful status message
- PrintWriter out = res.getWriter();
- processor.outputStatus(out);
- out.close();
- }
- }
- }
- catch (Throwable err)
- {
- throw new AlfrescoRuntimeException("Error during command servlet processing: " + err.getMessage(), err);
- }
- }
-
- /**
- * ALF-9113 CommandServlet.java, line 179 (Header Manipulation)
- *
- * Validates that the redirect page is within the current context.
- *
- * Examples of valid redirect pages:
- *
- *
/alfresco/faces/jsp/browse/browse.jsp
- *
../../browse/browse.jsp
- *
- *
- * @param pageUrl
- * @param req
- * @throws MalformedURLException
- * @throws IllegalArgumentException
- */
- private void validateReturnPage(String pageUrl, HttpServletRequest req) throws MalformedURLException
- {
- if (pageUrl.indexOf(':') != -1)
- {
- // ':' only allowed in a URL as part of a scheme prefix
- throw new IllegalArgumentException("The redirect URL doesn't support absolute URls");
- }
- // Evaluate it relative to the request URL and strip out .. and .
- pageUrl = new URL(new URL(req.getRequestURL().toString()), pageUrl).getPath();
- if (!pageUrl.startsWith(req.getContextPath()))
- {
- throw new IllegalArgumentException("The redirect URL must be in the same context.");
- }
- }
-
- /**
- * Created the specified CommandProcessor instance. The name of the processor is looked up
- * in the client config, it should find a valid class impl and then create it.
- *
- * @param procName Name of the CommandProcessor to lookup in the client config.
- *
- * @return CommandProcessor
- *
- * @throws InstantiationException
- * @throws IllegalAccessException
- */
- private CommandProcessor createCommandProcessor(String procName)
- throws InstantiationException, IllegalAccessException
- {
- Config config = Application.getConfigService(getServletContext()).getConfig("Command Servlet");
- if (config == null)
- {
- throw new AlfrescoRuntimeException("No command processors configured - unable to process any commands.");
- }
-
- CommandServletConfigElement configElement = (CommandServletConfigElement)
- config.getConfigElement(CommandServletConfigElement.CONFIG_ELEMENT_ID);
- if (configElement == null)
- {
- throw new AlfrescoRuntimeException("No command processors configured - unable to process any commands.");
- }
-
- Class clazz = configElement.getCommandProcessor(procName);
- Object obj = clazz.newInstance();
- if (obj instanceof CommandProcessor == false)
- {
- throw new AlfrescoRuntimeException("Configured command processor '" + procName + "' is does not implement interface CommandProcessor!");
- }
-
- return (CommandProcessor)obj;
- }
-}
+package org.alfresco.web.app.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+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.springframework.extensions.config.Config;
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.web.app.Application;
+import org.alfresco.web.app.servlet.command.CommandFactory;
+import org.alfresco.web.app.servlet.command.CommandProcessor;
+import org.alfresco.web.app.servlet.command.ExtCommandProcessor;
+import org.alfresco.web.config.CommandServletConfigElement;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Servlet responsible for executing commands upon node(s).
+ *
+ * The URL to the servlet should be generated thus:
+ *
+ * The 'processor-name' identifies the command processor to execute the command. For example the
+ * 'workflow' processor will execute workflow commands upon a node (e.g. "approve" or "reject").
+ * For example:
+ *
+ * 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.
+ *
+ * A 'return-page' URL argument can be specified as the redirect page to navigate too after processing.
+ *
+ * Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
+ * ?ticket=1234567890
+ *
+ * And/or also followed by the "?guest=true" argument to force guest access login for the URL.
+ *
+ * @author Kevin Roast
+ * @deprecated 5.0 not exposed in web-client web.xml
+ */
+public class CommandServlet extends BaseServlet
+{
+ private static final long serialVersionUID = -5432407921038376133L;
+
+ private static Log logger = LogFactory.getLog(CommandServlet.class);
+
+ private static CommandFactory commandfactory = CommandFactory.getInstance();
+
+ public static final String ARG_RETURNPAGE = "return-page";
+
+ /**
+ * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ protected void service(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;
+ }
+
+ setNoCacheHeaders(res);
+
+ uri = uri.substring(req.getContextPath().length());
+ StringTokenizer t = new StringTokenizer(uri, "/");
+ int tokenCount = t.countTokens();
+ if (tokenCount < 3)
+ {
+ throw new IllegalArgumentException("Command Servlet URL did not contain all required args: " + uri);
+ }
+
+ t.nextToken(); // skip servlet name
+
+ // get the command processor to execute the command e.g. "workflow"
+ String procName = t.nextToken();
+
+ // get the command to perform
+ String command = t.nextToken();
+
+ // get any remaining uri elements to pass to the processor
+ String[] urlElements = new String[tokenCount - 3];
+ for (int i=0; i args = new HashMap(8, 1.0f);
+ Enumeration names = req.getParameterNames();
+ while (names.hasMoreElements())
+ {
+ String name = (String)names.nextElement();
+ args.put(name, req.getParameter(name));
+ }
+
+ try
+ {
+ // get configured command processor by name from Config Service
+ CommandProcessor processor = createCommandProcessor(procName);
+
+ // validate that the processor has everything it needs to run the command
+ if (processor.validateArguments(getServletContext(), command, args, urlElements) == false)
+ {
+ redirectToLoginPage(req, res, getServletContext());
+ return;
+ }
+
+ ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
+ UserTransaction txn = null;
+ try
+ {
+ txn = serviceRegistry.getTransactionService().getUserTransaction();
+ txn.begin();
+
+ // inform the processor to execute the specified command
+ if (processor instanceof ExtCommandProcessor)
+ {
+ ((ExtCommandProcessor)processor).process(serviceRegistry, req, res, command);
+ }
+ else
+ {
+ processor.process(serviceRegistry, req, command);
+ }
+
+ // commit the transaction
+ txn.commit();
+ }
+ catch (Throwable txnErr)
+ {
+ try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
+ throw txnErr;
+ }
+
+ String returnPage = req.getParameter(ARG_RETURNPAGE);
+ if (returnPage != null && returnPage.length() != 0)
+ {
+ validateReturnPage(returnPage, req);
+ 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.");
+
+ if (res.getContentType() == null && !res.isCommitted())
+ {
+ res.setContentType("text/html");
+
+ // request that the processor output a useful status message
+ PrintWriter out = res.getWriter();
+ processor.outputStatus(out);
+ out.close();
+ }
+ }
+ }
+ catch (Throwable err)
+ {
+ throw new AlfrescoRuntimeException("Error during command servlet processing: " + err.getMessage(), err);
+ }
+ }
+
+ /**
+ * ALF-9113 CommandServlet.java, line 179 (Header Manipulation)
+ *
+ * Validates that the redirect page is within the current context.
+ *
+ * Examples of valid redirect pages:
+ *
+ *
/alfresco/faces/jsp/browse/browse.jsp
+ *
../../browse/browse.jsp
+ *
+ *
+ * @param pageUrl
+ * @param req
+ * @throws MalformedURLException
+ * @throws IllegalArgumentException
+ */
+ private void validateReturnPage(String pageUrl, HttpServletRequest req) throws MalformedURLException
+ {
+ if (pageUrl.indexOf(':') != -1)
+ {
+ // ':' only allowed in a URL as part of a scheme prefix
+ throw new IllegalArgumentException("The redirect URL doesn't support absolute URls");
+ }
+ // Evaluate it relative to the request URL and strip out .. and .
+ pageUrl = new URL(new URL(req.getRequestURL().toString()), pageUrl).getPath();
+ if (!pageUrl.startsWith(req.getContextPath()))
+ {
+ throw new IllegalArgumentException("The redirect URL must be in the same context.");
+ }
+ }
+
+ /**
+ * Created the specified CommandProcessor instance. The name of the processor is looked up
+ * in the client config, it should find a valid class impl and then create it.
+ *
+ * @param procName Name of the CommandProcessor to lookup in the client config.
+ *
+ * @return CommandProcessor
+ *
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ */
+ private CommandProcessor createCommandProcessor(String procName)
+ throws InstantiationException, IllegalAccessException
+ {
+ Config config = Application.getConfigService(getServletContext()).getConfig("Command Servlet");
+ if (config == null)
+ {
+ throw new AlfrescoRuntimeException("No command processors configured - unable to process any commands.");
+ }
+
+ CommandServletConfigElement configElement = (CommandServletConfigElement)
+ config.getConfigElement(CommandServletConfigElement.CONFIG_ELEMENT_ID);
+ if (configElement == null)
+ {
+ throw new AlfrescoRuntimeException("No command processors configured - unable to process any commands.");
+ }
+
+ Class clazz = configElement.getCommandProcessor(procName);
+ Object obj = clazz.newInstance();
+ if (obj instanceof CommandProcessor == false)
+ {
+ throw new AlfrescoRuntimeException("Configured command processor '" + procName + "' is does not implement interface CommandProcessor!");
+ }
+
+ return (CommandProcessor)obj;
+ }
+}
diff --git a/source/java/org/alfresco/web/app/servlet/FacesHelper.java b/source/java/org/alfresco/web/app/servlet/FacesHelper.java
index e09ecf526e..c58e116773 100644
--- a/source/java/org/alfresco/web/app/servlet/FacesHelper.java
+++ b/source/java/org/alfresco/web/app/servlet/FacesHelper.java
@@ -1,320 +1,320 @@
-package org.alfresco.web.app.servlet;
-
-import javax.faces.FactoryFinder;
-import javax.faces.component.UIComponent;
-import javax.faces.component.UIViewRoot;
-import javax.faces.context.FacesContext;
-import javax.faces.context.FacesContextFactory;
-import javax.faces.el.EvaluationException;
-import javax.faces.el.ValueBinding;
-import javax.faces.lifecycle.Lifecycle;
-import javax.faces.lifecycle.LifecycleFactory;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-import org.alfresco.error.AlfrescoRuntimeException;
-import org.alfresco.web.bean.generator.IComponentGenerator;
-import org.alfresco.web.ui.repo.RepoConstants;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * @author Kevin Roast
- */
-public final class FacesHelper
-{
- /** Root browse screen JSF view ID */
- public static final String BROWSE_VIEW_ID = "/jsp/browse/browse.jsp";
-
- private static Log logger = LogFactory.getLog(FacesHelper.class);
-
- /**
- * Mask for hex encoding
- */
- private static final int MASK = (1 << 4) - 1;
-
- /**
- * Digits used for hex string encoding
- */
- private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-
-
- /**
- * Private constructor
- */
- private FacesHelper()
- {
- }
-
- /**
- * Return a valid FacesContext for the specific context, request and response.
- * The FacesContext can be constructor for Servlet use.
- *
- * @param context ServletContext
- * @param request ServletRequest
- * @param response ServletReponse
- *
- * @return FacesContext
- */
- public static FacesContext getFacesContext(ServletRequest request, ServletResponse response, ServletContext context)
- {
- return getFacesContextImpl(request, response, context, null);
- }
-
- /**
- * Return a valid FacesContext for the specific context, request and response.
- * The FacesContext can be constructor for Servlet use.
- *
- * @param context ServletContext
- * @param request ServletRequest
- * @param response ServletReponse
- *
- * @return FacesContext
- */
- public static FacesContext getFacesContext(ServletRequest request, ServletResponse response, ServletContext context, String viewRoot)
- {
- return getFacesContextImpl(request, response, context, viewRoot);
- }
-
- /**
- * Return a valid FacesContext for the specific context, request and response.
- * The FacesContext can be constructor for Servlet use.
- *
- * @param context PortletContext
- * @param request PortletRequest
- * @param response PortletResponse
- *
- * @return FacesContext
- */
- public static FacesContext getFacesContext(Object request, Object response, Object context)
- {
- return getFacesContextImpl(request, response, context, null);
- }
-
- /**
- * Return a valid FacesContext for the specific context, request and response.
- * The FacesContext can be constructor for Servlet and Portlet use.
- *
- * @param context ServletContext or PortletContext
- * @param request ServletRequest or PortletRequest
- * @param response ServletReponse or PortletResponse
- *
- * @return FacesContext
- */
- private static FacesContext getFacesContextImpl(Object request, Object response, Object context, String viewRoot)
- {
- FacesContextFactory contextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
- LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
- Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
-
- // Doesn't set this instance as the current instance of FacesContext.getCurrentInstance
- FacesContext facesContext = contextFactory.getFacesContext(context, request, response, lifecycle);
-
- // Set using our inner class
- InnerFacesContext.setFacesContextAsCurrent(facesContext);
-
- // set a new viewRoot, otherwise context.getViewRoot returns null
- if (viewRoot == null)
- {
- viewRoot = FacesHelper.BROWSE_VIEW_ID;
- }
-
- UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, viewRoot);
- facesContext.setViewRoot(view);
-
- return facesContext;
- }
-
- /**
- * Return a JSF managed bean reference.
- *
- * @param fc FacesContext
- * @param name Name of the managed bean to return
- *
- * @return the managed bean or null if not found
- */
- public static Object getManagedBean(FacesContext fc, String name)
- {
- Object obj = null;
-
- try
- {
- ValueBinding vb = fc.getApplication().createValueBinding("#{" + name + "}");
- obj = vb.getValue(fc);
- }
- catch (EvaluationException ee)
- {
- // catch exception to resolve ADB-158/ACT-7343
- // not much we can do here, just make sure return is null
- if (logger.isDebugEnabled())
- logger.debug("Failed to resolve managed bean: " + name, ee);
- obj = null;
- }
-
- return obj;
- }
-
- /**
- * Sets up the id for the given component, if the id is null a unique one
- * is generated using the standard Faces algorithm. If an id is present it
- * is checked for illegal characters.
- *
- * @param context FacesContext
- * @param component The component to set the id for
- * @param id The id to set
- */
- public static void setupComponentId(FacesContext context, UIComponent component, String id)
- {
- if (id == null)
- {
- id = context.getViewRoot().createUniqueId();
- }
- else
- {
- // make sure we do not have illegal characters in the id
- id = makeLegalId(id);
- }
-
- component.setId(id);
- }
-
- /**
- * Makes the given id a legal JSF component id by replacing illegal characters
- * with ISO9075 encoding - which itself a subset of valid HTML ID characters.
- *
- * @param id The id to make legal
- *
- * @return the legalised id
- */
- public static String makeLegalId(String id)
- {
- return (id != null ? validFacesId(id) : null);
- }
-
- /**
- * Retrieves the named component generator implementation.
- * If the named generator is not found the TextFieldGenerator is looked up
- * as a default, if this is also not found an AlfrescoRuntimeException is thrown.
- *
- * @param context FacesContext
- * @param generatorName The name of the component generator to retrieve
- * @return The component generator instance
- */
- public static IComponentGenerator getComponentGenerator(FacesContext context, String generatorName)
- {
- IComponentGenerator generator = lookupComponentGenerator(context, generatorName);
-
- if (generator == null)
- {
- // create a text field if we can't find a component generator (a warning should have already been
- // displayed on the appserver console)
-
- logger.warn("Attempting to find default component generator '" + RepoConstants.GENERATOR_TEXT_FIELD + "'");
- generator = lookupComponentGenerator(context, RepoConstants.GENERATOR_TEXT_FIELD);
- }
-
- // if we still don't have a component generator we should abort as vital configuration is missing
- if (generator == null)
- {
- throw new AlfrescoRuntimeException("Failed to find a component generator, please ensure the '" +
- RepoConstants.GENERATOR_TEXT_FIELD + "' bean is present in your configuration");
- }
-
- return generator;
- }
-
- private static IComponentGenerator lookupComponentGenerator(FacesContext context, String generatorName)
- {
- IComponentGenerator generator = null;
-
- Object obj = FacesHelper.getManagedBean(context, generatorName);
- if (obj != null)
- {
- if (obj instanceof IComponentGenerator)
- {
- generator = (IComponentGenerator)obj;
-
- if (logger.isDebugEnabled())
- logger.debug("Found component generator for '" + generatorName + "': " + generator);
- }
- else
- {
- logger.warn("Bean '" + generatorName + "' does not implement IComponentGenerator");
- }
- }
- else
- {
- logger.warn("Failed to find component generator with name of '" + generatorName + "'");
- }
-
- return generator;
- }
-
- /**
- * We need an inner class to be able to call FacesContext.setCurrentInstance
- * since it's a protected method
- */
- private abstract static class InnerFacesContext extends FacesContext
- {
- protected static void setFacesContextAsCurrent(FacesContext facesContext)
- {
- FacesContext.setCurrentInstance(facesContext);
- }
- }
-
- /**
- * Helper to ensure only valid and acceptable characters are output as Faces component IDs.
- * Based on ISO9075 encoding - which itself a subset of valid HTML ID characters.
- */
- private static String validFacesId(String id)
- {
- int len = id.length();
- StringBuilder buf = new StringBuilder(len + (len>>1));
- for (int i = 0; i= 65 && ci <= 90) || // A-Z
- (ci >= 97 && ci <= 122)) // a-z
- {
- buf.append(c);
- }
- else
- {
- encode(c, buf);
- }
- }
- else
- {
- if ((ci >= 65 && ci <= 90) || // A-Z
- (ci >= 97 && ci <= 122) || // a-z
- (ci >= 48 && ci <= 57) || // 0-9
- ci == 45 || ci == 95) // - and _
- {
- buf.append(c);
- }
- else
- {
- encode(c, buf);
- }
- }
- }
- return buf.toString();
- }
-
- private static void encode(char c, StringBuilder builder)
- {
- char[] buf = new char[] { 'x', '0', '0', '0', '0', '_' };
- int charPos = 5;
- do
- {
- buf[--charPos] = DIGITS[c & MASK];
- c >>>= 4;
- }
- while (c != 0);
- builder.append(buf);
- }
-}
+package org.alfresco.web.app.servlet;
+
+import javax.faces.FactoryFinder;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.context.FacesContextFactory;
+import javax.faces.el.EvaluationException;
+import javax.faces.el.ValueBinding;
+import javax.faces.lifecycle.Lifecycle;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.web.bean.generator.IComponentGenerator;
+import org.alfresco.web.ui.repo.RepoConstants;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Kevin Roast
+ */
+public final class FacesHelper
+{
+ /** Root browse screen JSF view ID */
+ public static final String BROWSE_VIEW_ID = "/jsp/browse/browse.jsp";
+
+ private static Log logger = LogFactory.getLog(FacesHelper.class);
+
+ /**
+ * Mask for hex encoding
+ */
+ private static final int MASK = (1 << 4) - 1;
+
+ /**
+ * Digits used for hex string encoding
+ */
+ private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+
+ /**
+ * Private constructor
+ */
+ private FacesHelper()
+ {
+ }
+
+ /**
+ * Return a valid FacesContext for the specific context, request and response.
+ * The FacesContext can be constructor for Servlet use.
+ *
+ * @param context ServletContext
+ * @param request ServletRequest
+ * @param response ServletReponse
+ *
+ * @return FacesContext
+ */
+ public static FacesContext getFacesContext(ServletRequest request, ServletResponse response, ServletContext context)
+ {
+ return getFacesContextImpl(request, response, context, null);
+ }
+
+ /**
+ * Return a valid FacesContext for the specific context, request and response.
+ * The FacesContext can be constructor for Servlet use.
+ *
+ * @param context ServletContext
+ * @param request ServletRequest
+ * @param response ServletReponse
+ *
+ * @return FacesContext
+ */
+ public static FacesContext getFacesContext(ServletRequest request, ServletResponse response, ServletContext context, String viewRoot)
+ {
+ return getFacesContextImpl(request, response, context, viewRoot);
+ }
+
+ /**
+ * Return a valid FacesContext for the specific context, request and response.
+ * The FacesContext can be constructor for Servlet use.
+ *
+ * @param context PortletContext
+ * @param request PortletRequest
+ * @param response PortletResponse
+ *
+ * @return FacesContext
+ */
+ public static FacesContext getFacesContext(Object request, Object response, Object context)
+ {
+ return getFacesContextImpl(request, response, context, null);
+ }
+
+ /**
+ * Return a valid FacesContext for the specific context, request and response.
+ * The FacesContext can be constructor for Servlet and Portlet use.
+ *
+ * @param context ServletContext or PortletContext
+ * @param request ServletRequest or PortletRequest
+ * @param response ServletReponse or PortletResponse
+ *
+ * @return FacesContext
+ */
+ private static FacesContext getFacesContextImpl(Object request, Object response, Object context, String viewRoot)
+ {
+ FacesContextFactory contextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
+ LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+ Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
+
+ // Doesn't set this instance as the current instance of FacesContext.getCurrentInstance
+ FacesContext facesContext = contextFactory.getFacesContext(context, request, response, lifecycle);
+
+ // Set using our inner class
+ InnerFacesContext.setFacesContextAsCurrent(facesContext);
+
+ // set a new viewRoot, otherwise context.getViewRoot returns null
+ if (viewRoot == null)
+ {
+ viewRoot = FacesHelper.BROWSE_VIEW_ID;
+ }
+
+ UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, viewRoot);
+ facesContext.setViewRoot(view);
+
+ return facesContext;
+ }
+
+ /**
+ * Return a JSF managed bean reference.
+ *
+ * @param fc FacesContext
+ * @param name Name of the managed bean to return
+ *
+ * @return the managed bean or null if not found
+ */
+ public static Object getManagedBean(FacesContext fc, String name)
+ {
+ Object obj = null;
+
+ try
+ {
+ ValueBinding vb = fc.getApplication().createValueBinding("#{" + name + "}");
+ obj = vb.getValue(fc);
+ }
+ catch (EvaluationException ee)
+ {
+ // catch exception to resolve ADB-158/ACT-7343
+ // not much we can do here, just make sure return is null
+ if (logger.isDebugEnabled())
+ logger.debug("Failed to resolve managed bean: " + name, ee);
+ obj = null;
+ }
+
+ return obj;
+ }
+
+ /**
+ * Sets up the id for the given component, if the id is null a unique one
+ * is generated using the standard Faces algorithm. If an id is present it
+ * is checked for illegal characters.
+ *
+ * @param context FacesContext
+ * @param component The component to set the id for
+ * @param id The id to set
+ */
+ public static void setupComponentId(FacesContext context, UIComponent component, String id)
+ {
+ if (id == null)
+ {
+ id = context.getViewRoot().createUniqueId();
+ }
+ else
+ {
+ // make sure we do not have illegal characters in the id
+ id = makeLegalId(id);
+ }
+
+ component.setId(id);
+ }
+
+ /**
+ * Makes the given id a legal JSF component id by replacing illegal characters
+ * with ISO9075 encoding - which itself a subset of valid HTML ID characters.
+ *
+ * @param id The id to make legal
+ *
+ * @return the legalised id
+ */
+ public static String makeLegalId(String id)
+ {
+ return (id != null ? validFacesId(id) : null);
+ }
+
+ /**
+ * Retrieves the named component generator implementation.
+ * If the named generator is not found the TextFieldGenerator is looked up
+ * as a default, if this is also not found an AlfrescoRuntimeException is thrown.
+ *
+ * @param context FacesContext
+ * @param generatorName The name of the component generator to retrieve
+ * @return The component generator instance
+ */
+ public static IComponentGenerator getComponentGenerator(FacesContext context, String generatorName)
+ {
+ IComponentGenerator generator = lookupComponentGenerator(context, generatorName);
+
+ if (generator == null)
+ {
+ // create a text field if we can't find a component generator (a warning should have already been
+ // displayed on the appserver console)
+
+ logger.warn("Attempting to find default component generator '" + RepoConstants.GENERATOR_TEXT_FIELD + "'");
+ generator = lookupComponentGenerator(context, RepoConstants.GENERATOR_TEXT_FIELD);
+ }
+
+ // if we still don't have a component generator we should abort as vital configuration is missing
+ if (generator == null)
+ {
+ throw new AlfrescoRuntimeException("Failed to find a component generator, please ensure the '" +
+ RepoConstants.GENERATOR_TEXT_FIELD + "' bean is present in your configuration");
+ }
+
+ return generator;
+ }
+
+ private static IComponentGenerator lookupComponentGenerator(FacesContext context, String generatorName)
+ {
+ IComponentGenerator generator = null;
+
+ Object obj = FacesHelper.getManagedBean(context, generatorName);
+ if (obj != null)
+ {
+ if (obj instanceof IComponentGenerator)
+ {
+ generator = (IComponentGenerator)obj;
+
+ if (logger.isDebugEnabled())
+ logger.debug("Found component generator for '" + generatorName + "': " + generator);
+ }
+ else
+ {
+ logger.warn("Bean '" + generatorName + "' does not implement IComponentGenerator");
+ }
+ }
+ else
+ {
+ logger.warn("Failed to find component generator with name of '" + generatorName + "'");
+ }
+
+ return generator;
+ }
+
+ /**
+ * We need an inner class to be able to call FacesContext.setCurrentInstance
+ * since it's a protected method
+ */
+ private abstract static class InnerFacesContext extends FacesContext
+ {
+ protected static void setFacesContextAsCurrent(FacesContext facesContext)
+ {
+ FacesContext.setCurrentInstance(facesContext);
+ }
+ }
+
+ /**
+ * Helper to ensure only valid and acceptable characters are output as Faces component IDs.
+ * Based on ISO9075 encoding - which itself a subset of valid HTML ID characters.
+ */
+ private static String validFacesId(String id)
+ {
+ int len = id.length();
+ StringBuilder buf = new StringBuilder(len + (len>>1));
+ for (int i = 0; i= 65 && ci <= 90) || // A-Z
+ (ci >= 97 && ci <= 122)) // a-z
+ {
+ buf.append(c);
+ }
+ else
+ {
+ encode(c, buf);
+ }
+ }
+ else
+ {
+ if ((ci >= 65 && ci <= 90) || // A-Z
+ (ci >= 97 && ci <= 122) || // a-z
+ (ci >= 48 && ci <= 57) || // 0-9
+ ci == 45 || ci == 95) // - and _
+ {
+ buf.append(c);
+ }
+ else
+ {
+ encode(c, buf);
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ private static void encode(char c, StringBuilder builder)
+ {
+ char[] buf = new char[] { 'x', '0', '0', '0', '0', '_' };
+ int charPos = 5;
+ do
+ {
+ buf[--charPos] = DIGITS[c & MASK];
+ c >>>= 4;
+ }
+ while (c != 0);
+ builder.append(buf);
+ }
+}
diff --git a/source/java/org/alfresco/web/app/servlet/GuestDownloadContentServlet.java b/source/java/org/alfresco/web/app/servlet/GuestDownloadContentServlet.java
index 77efb3c717..858b0b97b1 100644
--- a/source/java/org/alfresco/web/app/servlet/GuestDownloadContentServlet.java
+++ b/source/java/org/alfresco/web/app/servlet/GuestDownloadContentServlet.java
@@ -1,130 +1,130 @@
-package org.alfresco.web.app.servlet;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.alfresco.repo.security.authentication.AuthenticationUtil;
-import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Servlet responsible for streaming node content from the repo directly to the response stream.
- * The appropriate mimetype is calculated based on filename extension.
- *
- * The URL to the servlet should be generated thus:
- *
- * The protocol, followed by either the store and Id (NodeRef) or instead specify a name based
- * encoded Path to the content, note that the filename element is used for mimetype lookup and
- * as the returning filename for the response stream.
- *
- * The 'attach' or 'direct' element is used to indicate whether to display the stream directly
- * in the browser or download it as a file attachment.
- *
- * By default, the download assumes that the content is on the
- * {@link org.alfresco.model.ContentModel#PROP_CONTENT content property}.
- * To retrieve the content of a specific model property, use a 'property' arg, providing the workspace,
- * node ID AND the qualified name of the property.
- *
- * This servlet only accesses content available to the guest user. If the guest user does not
- * have access to the requested a 403 Forbidden response is returned to the caller.
- *
- * This servlet does not effect the current session, therefore if guest access is required to a
- * resource this servlet can be used without logging out the current user.
- *
- * @author gavinc
- */
-public class GuestDownloadContentServlet extends BaseDownloadContentServlet
-{
- private static final long serialVersionUID = -5258137503339817457L;
-
- private static Log logger = LogFactory.getLog(GuestDownloadContentServlet.class);
-
- private static final String DOWNLOAD_URL = "/gd/" + URL_ATTACH + "/{0}/{1}/{2}/{3}";
- private static final String BROWSER_URL = "/gd/" + URL_DIRECT + "/{0}/{1}/{2}/{3}";
-
- @Override
- protected Log getLogger()
- {
- return logger;
- }
-
- /**
- * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
- */
- protected void doGet(HttpServletRequest req, HttpServletResponse res)
- throws ServletException, IOException
- {
- if (logger.isDebugEnabled())
- {
- String queryString = req.getQueryString();
- logger.debug("Setting up guest access to URL: " + req.getRequestURI() +
- ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
- }
-
- DownloadContentWork dcw = new DownloadContentWork(req, res);
- AuthenticationUtil.runAs(dcw, AuthenticationUtil.getGuestUserName());
- }
-
- /**
- * Helper to generate a URL to a content node for downloading content from the server.
- * The content is supplied as an HTTP1.1 attachment to the response. This generally means
- * a browser should prompt the user to save the content to specified location.
- *
- * @param ref NodeRef of the content node to generate URL for (cannot be null)
- * @param name File name to return in the URL (cannot be null)
- *
- * @return URL to download the content from the specified node
- */
- public final static String generateDownloadURL(NodeRef ref, String name)
- {
- return generateUrl(DOWNLOAD_URL, ref, name);
- }
-
- /**
- * Helper to generate a URL to a content node for downloading content from the server.
- * The content is supplied directly in the reponse. This generally means a browser will
- * attempt to open the content directly if possible, else it will prompt to save the file.
- *
- * @param ref NodeRef of the content node to generate URL for (cannot be null)
- * @param name File name to return in the URL (cannot be null)
- *
- * @return URL to download the content from the specified node
- */
- public final static String generateBrowserURL(NodeRef ref, String name)
- {
- return generateUrl(BROWSER_URL, ref, name);
- }
-
- /**
- * Class to wrap the call to processDownloadRequest.
- *
- * @author gavinc
- */
- public class DownloadContentWork implements RunAsWork