diff --git a/source/java/org/alfresco/web/action/evaluator/WCMLockEvaluator.java b/source/java/org/alfresco/web/action/evaluator/WCMLockEvaluator.java new file mode 100644 index 0000000000..364522b110 --- /dev/null +++ b/source/java/org/alfresco/web/action/evaluator/WCMLockEvaluator.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.action.evaluator; + +import javax.faces.context.FacesContext; + +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.service.cmr.avm.locking.AVMLockingService; +import org.alfresco.web.action.ActionEvaluator; +import org.alfresco.web.app.Application; +import org.alfresco.web.app.servlet.FacesHelper; +import org.alfresco.web.bean.repository.Node; +import org.alfresco.web.bean.repository.Repository; +import org.alfresco.web.bean.wcm.AVMBrowseBean; + +/** + * Evaluator to return if a item is accessable due to a WCM user level lock. + * + * @author Kevin Roast + */ +public class WCMLockEvaluator implements ActionEvaluator +{ + /** + * @return true if the item is not locked by another user + */ + public boolean evaluate(Node node) + { + FacesContext fc = FacesContext.getCurrentInstance(); + AVMLockingService avmLockService = Repository.getServiceRegistry(fc).getAVMLockingService(); + AVMBrowseBean avmBrowseBean = (AVMBrowseBean)FacesHelper.getManagedBean(fc, AVMBrowseBean.BEAN_NAME); + + String path = AVMNodeConverter.ToAVMVersionPath(node.getNodeRef()).getSecond(); + String username = Application.getCurrentUser(fc).getUserName(); + + return avmLockService.hasAccess(avmBrowseBean.getWebProject().getNodeRef(), path, username); + } +} diff --git a/source/java/org/alfresco/web/action/evaluator/WCMWorkflowDeletedEvaluator.java b/source/java/org/alfresco/web/action/evaluator/WCMWorkflowDeletedEvaluator.java index 9687a11538..42ca0fcd4e 100644 --- a/source/java/org/alfresco/web/action/evaluator/WCMWorkflowDeletedEvaluator.java +++ b/source/java/org/alfresco/web/action/evaluator/WCMWorkflowDeletedEvaluator.java @@ -30,7 +30,6 @@ import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.avm.wf.AVMSubmittedAspect; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.util.Pair; -import org.alfresco.web.action.ActionEvaluator; import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.bean.wcm.AVMUtil; @@ -41,22 +40,27 @@ import org.alfresco.web.bean.wcm.AVMUtil; * * @author Kevin Roast */ -public class WCMWorkflowDeletedEvaluator implements ActionEvaluator +public class WCMWorkflowDeletedEvaluator extends WCMLockEvaluator { /** * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node) */ public boolean evaluate(final Node node) { - final FacesContext facesContext = FacesContext.getCurrentInstance(); - final AVMService avmService = Repository.getServiceRegistry(facesContext).getAVMService(); - final Pair p = AVMNodeConverter.ToAVMVersionPath(node.getNodeRef()); - final int version = p.getFirst(); - final String path = p.getSecond(); - - // evaluate to true if we are within a workflow store (i.e. list of resources in the task - // dialog) or not part of an already in-progress workflow - return (AVMUtil.isWorkflowStore(AVMUtil.getStoreName(path)) || - avmService.hasAspect(version, path, AVMSubmittedAspect.ASPECT) == false); + boolean proceed = false; + if (super.evaluate(node)) + { + final FacesContext facesContext = FacesContext.getCurrentInstance(); + final AVMService avmService = Repository.getServiceRegistry(facesContext).getAVMService(); + final Pair p = AVMNodeConverter.ToAVMVersionPath(node.getNodeRef()); + final int version = p.getFirst(); + final String path = p.getSecond(); + + // evaluate to true if we are within a workflow store (i.e. list of resources in the task + // dialog) or not part of an already in-progress workflow + proceed = (AVMUtil.isWorkflowStore(AVMUtil.getStoreName(path)) || + avmService.hasAspect(version, path, AVMSubmittedAspect.ASPECT) == false); + } + return proceed; } -} +} \ No newline at end of file diff --git a/source/java/org/alfresco/web/action/evaluator/WCMWorkflowEvaluator.java b/source/java/org/alfresco/web/action/evaluator/WCMWorkflowEvaluator.java index 9dbd9d91b3..3ed2871a05 100644 --- a/source/java/org/alfresco/web/action/evaluator/WCMWorkflowEvaluator.java +++ b/source/java/org/alfresco/web/action/evaluator/WCMWorkflowEvaluator.java @@ -30,7 +30,6 @@ import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.avm.wf.AVMSubmittedAspect; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.util.Pair; -import org.alfresco.web.action.ActionEvaluator; import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.bean.wcm.AVMUtil; @@ -40,23 +39,28 @@ import org.alfresco.web.bean.wcm.AVMUtil; * * @author Kevin Roast */ -public class WCMWorkflowEvaluator implements ActionEvaluator +public class WCMWorkflowEvaluator extends WCMLockEvaluator { /** * @see org.alfresco.web.action.ActionEvaluator#evaluate(org.alfresco.web.bean.repository.Node) */ public boolean evaluate(final Node node) { - final FacesContext facesContext = FacesContext.getCurrentInstance(); - final AVMService avmService = Repository.getServiceRegistry(facesContext).getAVMService(); - final Pair p = AVMNodeConverter.ToAVMVersionPath(node.getNodeRef()); - final int version = p.getFirst(); - final String path = p.getSecond(); - - // evaluate to true if we are not deleted and within a workflow store (i.e. list of resources - // in the task dialog) or not part of an already in-progress workflow - return ((AVMUtil.isWorkflowStore(AVMUtil.getStoreName(path)) || - avmService.hasAspect(version, path, AVMSubmittedAspect.ASPECT) == false) && - avmService.lookup(version, path) != null); + boolean proceed = false; + if (super.evaluate(node)) + { + final FacesContext facesContext = FacesContext.getCurrentInstance(); + final AVMService avmService = Repository.getServiceRegistry(facesContext).getAVMService(); + final Pair p = AVMNodeConverter.ToAVMVersionPath(node.getNodeRef()); + final int version = p.getFirst(); + final String path = p.getSecond(); + + // evaluate to true if we are not deleted and within a workflow store (i.e. list of resources + // in the task dialog) or not part of an already in-progress workflow + proceed = ((AVMUtil.isWorkflowStore(AVMUtil.getStoreName(path)) || + avmService.hasAspect(version, path, AVMSubmittedAspect.ASPECT) == false) && + avmService.lookup(version, path) != null); + } + return proceed; } } diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java index 76abd6bcab..ff614429d9 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java @@ -43,6 +43,7 @@ import org.alfresco.model.ContentModel; import org.alfresco.model.WCMAppModel; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avm.locking.AVMLockingService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.AuthorityType; @@ -88,8 +89,8 @@ public class CreateWebsiteWizard extends BaseWizardBean private static Log logger = LogFactory.getLog(CreateWebsiteWizard.class); protected boolean editMode = false; - protected String dnsName; + protected String title; protected String name; protected String description; @@ -99,6 +100,7 @@ public class CreateWebsiteWizard extends BaseWizardBean protected AVMService avmService; protected WorkflowService workflowService; protected PersonService personService; + protected AVMLockingService avmLockingService; /** datamodel for table of selected forms */ protected DataModel formsDataModel = null; @@ -217,6 +219,9 @@ public class CreateWebsiteWizard extends BaseWizardBean // navigate to the Websites folder so we can see the newly created folder this.navigator.setCurrentNodeId(websiteParent.getId()); + // inform the locking service about this new instance + this.avmLockingService.addWebProject(avmStore); + outcome = AlfrescoNavigationHandler.CLOSE_WIZARD_OUTCOME; } return outcome; @@ -370,6 +375,14 @@ public class CreateWebsiteWizard extends BaseWizardBean { this.personService = personService; } + + /** + * @param avmLockingService The AVMLockingService to set + */ + public void setAvmLockingService(AVMLockingService avmLockingService) + { + this.avmLockingService = avmLockingService; + } // ------------------------------------------------------------------------------ diff --git a/source/java/org/alfresco/web/bean/wcm/EditFilePropertiesDialog.java b/source/java/org/alfresco/web/bean/wcm/EditFilePropertiesDialog.java index 187f43193a..888bd9c6bc 100644 --- a/source/java/org/alfresco/web/bean/wcm/EditFilePropertiesDialog.java +++ b/source/java/org/alfresco/web/bean/wcm/EditFilePropertiesDialog.java @@ -26,7 +26,9 @@ package org.alfresco.web.bean.wcm; import java.io.Serializable; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import java.util.Map; import javax.faces.context.FacesContext; @@ -34,6 +36,9 @@ import javax.faces.context.FacesContext; import org.alfresco.model.ContentModel; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avm.locking.AVMLock; +import org.alfresco.service.cmr.avm.locking.AVMLockingException; +import org.alfresco.service.cmr.avm.locking.AVMLockingService; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.model.FileExistsException; @@ -55,7 +60,7 @@ public class EditFilePropertiesDialog extends EditContentPropertiesDialog { protected AVMBrowseBean avmBrowseBean; protected AVMService avmService; - + protected AVMLockingService avmLockingService; // ------------------------------------------------------------------------------ // Bean property getters and setters @@ -76,6 +81,14 @@ public class EditFilePropertiesDialog extends EditContentPropertiesDialog this.avmService = avmService; } + /** + * @param avmLockingService The AVMLockingService to set + */ + public void setAvmLockingService(AVMLockingService avmLockingService) + { + this.avmLockingService = avmLockingService; + } + // ------------------------------------------------------------------------------ // Dialog implementation @@ -93,77 +106,106 @@ public class EditFilePropertiesDialog extends EditContentPropertiesDialog throws Exception { NodeRef nodeRef = this.editableNode.getNodeRef(); - Map editedProps = this.editableNode.getProperties(); + String webProjectId = this.avmBrowseBean.getWebProject().getStoreId(); + String avmPath = AVMNodeConverter.ToAVMVersionPath(nodeRef).getSecond(); + String[] storePath = avmPath.split(":"); + String username = Application.getCurrentUser(context).getUserName(); - // handle the name property separately, it is a special case for AVM nodes - String name = (String)editedProps.get(ContentModel.PROP_NAME); - if (name != null) + try { - editedProps.remove(ContentModel.PROP_NAME); - } - - // we need to put all the properties from the editable bag back into - // the format expected by the repository - Map repoProps = this.nodeService.getProperties(nodeRef); - - // but first extract and deal with the special mimetype property for ContentData - String mimetype = (String)editedProps.get(TEMP_PROP_MIMETYPE); - if (mimetype != null) - { - // remove temporary prop from list so it isn't saved with the others - editedProps.remove(TEMP_PROP_MIMETYPE); - ContentData contentData = (ContentData)editedProps.get(ContentModel.PROP_CONTENT); - if (contentData != null) - { - contentData = ContentData.setMimetype(contentData, mimetype); - editedProps.put(ContentModel.PROP_CONTENT.toString(), contentData); + if (this.avmLockingService.hasAccess(webProjectId, avmPath, username) == false) + { + throw new AVMLockingException("avmlockservice.locked", new Object[]{avmPath}); } - } - - // add the "titled" aspect if required, properties will get set below - if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TITLED) == false) - { - nodeService.addAspect(nodeRef, ContentModel.ASPECT_TITLED, null); - } - - // add the remaining properties - Iterator iterProps = editedProps.keySet().iterator(); - while (iterProps.hasNext()) - { - String propName = iterProps.next(); - QName qname = QName.createQName(propName); - - // make sure the property is represented correctly - Serializable propValue = (Serializable)editedProps.get(propName); - - // check for empty strings when using number types, set to null in this case - if ((propValue != null) && (propValue instanceof String) && - (propValue.toString().length() == 0)) + else { - PropertyDefinition propDef = this.dictionaryService.getProperty(qname); - if (propDef != null) + if (this.avmLockingService.getLock(webProjectId, avmPath) == null) { - if (propDef.getDataType().getName().equals(DataTypeDefinition.DOUBLE) || - propDef.getDataType().getName().equals(DataTypeDefinition.FLOAT) || - propDef.getDataType().getName().equals(DataTypeDefinition.INT) || - propDef.getDataType().getName().equals(DataTypeDefinition.LONG)) - { - propValue = null; - } + List owners = new ArrayList(1); + owners.add(username); + AVMLock lock = new AVMLock(webProjectId, storePath[0], storePath[1], AVMLockingService.Type.DISCRETIONARY, owners); + this.avmLockingService.lockPath(lock); + } + } + Map editedProps = this.editableNode.getProperties(); + + // handle the name property separately, it is a special case for AVM nodes + String name = (String)editedProps.get(ContentModel.PROP_NAME); + if (name != null) + { + editedProps.remove(ContentModel.PROP_NAME); + } + + // we need to put all the properties from the editable bag back into + // the format expected by the repository + Map repoProps = this.nodeService.getProperties(nodeRef); + + // but first extract and deal with the special mimetype property for ContentData + String mimetype = (String)editedProps.get(TEMP_PROP_MIMETYPE); + if (mimetype != null) + { + // remove temporary prop from list so it isn't saved with the others + editedProps.remove(TEMP_PROP_MIMETYPE); + ContentData contentData = (ContentData)editedProps.get(ContentModel.PROP_CONTENT); + if (contentData != null) + { + contentData = ContentData.setMimetype(contentData, mimetype); + editedProps.put(ContentModel.PROP_CONTENT.toString(), contentData); } } - repoProps.put(qname, propValue); + // add the "titled" aspect if required, properties will get set below + if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TITLED) == false) + { + this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_TITLED, null); + } + + // add the remaining properties + Iterator iterProps = editedProps.keySet().iterator(); + while (iterProps.hasNext()) + { + String propName = iterProps.next(); + QName qname = QName.createQName(propName); + + // make sure the property is represented correctly + Serializable propValue = (Serializable)editedProps.get(propName); + + // check for empty strings when using number types, set to null in this case + if ((propValue != null) && (propValue instanceof String) && + (propValue.toString().length() == 0)) + { + PropertyDefinition propDef = this.dictionaryService.getProperty(qname); + if (propDef != null) + { + if (propDef.getDataType().getName().equals(DataTypeDefinition.DOUBLE) || + propDef.getDataType().getName().equals(DataTypeDefinition.FLOAT) || + propDef.getDataType().getName().equals(DataTypeDefinition.INT) || + propDef.getDataType().getName().equals(DataTypeDefinition.LONG)) + { + propValue = null; + } + } + } + + repoProps.put(qname, propValue); + } + + // send the properties back to the repository + this.nodeService.setProperties(nodeRef, repoProps); + + // perform the rename last as for an AVM it changes the NodeRef + if (name != null) + { + this.fileFolderService.rename(nodeRef, name); + editedProps.put(ContentModel.PROP_NAME.toString(), name); + } } - - // send the properties back to the repository - this.nodeService.setProperties(nodeRef, repoProps); - - // perform the rename last as for an AVM it changes the NodeRef - if (name != null) + finally { - this.fileFolderService.rename(nodeRef, name); - editedProps.put(ContentModel.PROP_NAME.toString(), name); + if (this.avmLockingService.getLock(webProjectId, avmPath) != null) + { + this.avmLockingService.removeLock(webProjectId, avmPath); + } } return outcome; diff --git a/source/java/org/alfresco/web/ui/repo/component/evaluator/ActionInstanceEvaluator.java b/source/java/org/alfresco/web/ui/repo/component/evaluator/ActionInstanceEvaluator.java index 5f568731b3..a4e265aec2 100644 --- a/source/java/org/alfresco/web/ui/repo/component/evaluator/ActionInstanceEvaluator.java +++ b/source/java/org/alfresco/web/ui/repo/component/evaluator/ActionInstanceEvaluator.java @@ -25,7 +25,10 @@ package org.alfresco.web.ui.repo.component.evaluator; import javax.faces.context.FacesContext; +import javax.faces.el.ValueBinding; +import org.alfresco.config.ConfigException; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.web.action.ActionEvaluator; import org.alfresco.web.bean.repository.Node; import org.alfresco.web.ui.common.component.evaluator.BaseEvaluator; @@ -72,6 +75,7 @@ public class ActionInstanceEvaluator extends BaseEvaluator // standard component attributes are restored by the super class super.restoreState(context, values[0]); this.evaluator = (ActionEvaluator)values[1]; + this.evaluatorClassName = (String)values[2]; } /** @@ -79,10 +83,11 @@ public class ActionInstanceEvaluator extends BaseEvaluator */ public Object saveState(FacesContext context) { - Object values[] = new Object[2]; - // standard component attributes are saved by the super class - values[0] = super.saveState(context); - values[1] = this.evaluator; + Object values[] = new Object[] { + // standard component attributes are saved by the super class + super.saveState(context), + this.evaluator, + this.evaluatorClassName }; return (values); } @@ -91,6 +96,24 @@ public class ActionInstanceEvaluator extends BaseEvaluator */ public ActionEvaluator getEvaluator() { + if (this.evaluator == null) + { + Object objEvaluator; + try + { + Class clazz = Class.forName(getEvaluatorClassName()); + objEvaluator = clazz.newInstance(); + } + catch (Throwable err) + { + throw new AlfrescoRuntimeException("Unable to construct action evaluator: " + getEvaluatorClassName()); + } + if (objEvaluator instanceof ActionEvaluator == false) + { + throw new AlfrescoRuntimeException("Must implement ActionEvaluator interface: " + getEvaluatorClassName()); + } + this.evaluator = (ActionEvaluator)objEvaluator; + } return this.evaluator; } @@ -102,6 +125,27 @@ public class ActionInstanceEvaluator extends BaseEvaluator this.evaluator = evaluator; } + /** + * @return the evaluatorClassName + */ + public String getEvaluatorClassName() + { + ValueBinding vb = getValueBinding("evaluatorClassName"); + if (vb != null) + { + this.evaluatorClassName = (String)vb.getValue(getFacesContext()); + } + return this.evaluatorClassName; + } + + /** + * @param evaluatorClassName the evaluatorClassName to set + */ + public void setEvaluatorClassName(String evaluatorClassName) + { + this.evaluatorClassName = evaluatorClassName; + } private ActionEvaluator evaluator; + private String evaluatorClassName; } diff --git a/source/java/org/alfresco/web/ui/repo/tag/evaluator/ActionInstanceEvaluatorTag.java b/source/java/org/alfresco/web/ui/repo/tag/evaluator/ActionInstanceEvaluatorTag.java index 11a8c2ea1c..aa233e6855 100644 --- a/source/java/org/alfresco/web/ui/repo/tag/evaluator/ActionInstanceEvaluatorTag.java +++ b/source/java/org/alfresco/web/ui/repo/tag/evaluator/ActionInstanceEvaluatorTag.java @@ -40,4 +40,36 @@ public class ActionInstanceEvaluatorTag extends GenericEvaluatorTag { return "org.alfresco.faces.ActionInstanceEvaluator"; } + + /** + * @see javax.faces.webapp.UIComponentTag#setProperties(javax.faces.component.UIComponent) + */ + protected void setProperties(UIComponent component) + { + super.setProperties(component); + setStringProperty(component, "evaluatorClassName", this.evaluatorClassName); + } + + /** + * @see javax.servlet.jsp.tagext.Tag#release() + */ + public void release() + { + super.release(); + this.evaluatorClassName = null; + } + + /** + * Set the evaluatorClassName + * + * @param evaluatorClassName the evaluatorClassName + */ + public void setEvaluatorClassName(String evaluatorClassName) + { + this.evaluatorClassName = evaluatorClassName; + } + + + /** the evaluatorClassName */ + private String evaluatorClassName; } diff --git a/source/web/WEB-INF/faces-config-beans.xml b/source/web/WEB-INF/faces-config-beans.xml index 660f1ffc2e..0878f5ca5c 100644 --- a/source/web/WEB-INF/faces-config-beans.xml +++ b/source/web/WEB-INF/faces-config-beans.xml @@ -2746,6 +2746,10 @@ personService #{PersonService} + + avmLockingService + #{AVMLockingService} + @@ -3196,6 +3200,10 @@ avmService #{AVMService} + + avmLockingService + #{AVMLockingService} + fileFolderService #{FileFolderService} diff --git a/source/web/WEB-INF/repo.tld b/source/web/WEB-INF/repo.tld index 6e2d68895c..5cb9c410ed 100644 --- a/source/web/WEB-INF/repo.tld +++ b/source/web/WEB-INF/repo.tld @@ -1466,6 +1466,36 @@ + + actionInstanceEvaluator + org.alfresco.web.ui.repo.tag.evaluator.ActionInstanceEvaluatorTag + JSP + + + id + false + true + + + + value + true + true + + + + evaluatorClassName + true + true + + + + binding + false + true + + + multiValueSelector org.alfresco.web.ui.repo.tag.MultiValueSelectorTag diff --git a/source/web/jsp/wcm/file-details.jsp b/source/web/jsp/wcm/file-details.jsp index 7d25607c4b..8d9fde2a5d 100644 --- a/source/web/jsp/wcm/file-details.jsp +++ b/source/web/jsp/wcm/file-details.jsp @@ -151,7 +151,9 @@ - + + +