Index: magnolia-module-admininterface/src/main/java/info/magnolia/module/admininterface/AdminTreeMVCHandler.java =================================================================== --- magnolia-module-admininterface/src/main/java/info/magnolia/module/admininterface/AdminTreeMVCHandler.java (revision 15750) +++ magnolia-module-admininterface/src/main/java/info/magnolia/module/admininterface/AdminTreeMVCHandler.java (working copy) @@ -187,6 +187,7 @@ public void init() { super.init(); + System.out.println("TEST asdfasdfasd"); path = this.getRequest().getParameter("path"); //$NON-NLS-1$ if (StringUtils.isEmpty(path)) { path = "/"; //$NON-NLS-1$ Index: magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/WorkflowModule.java =================================================================== --- magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/WorkflowModule.java (revision 15750) +++ magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/WorkflowModule.java (working copy) @@ -72,11 +72,6 @@ */ private boolean backupWorkItems = false; - /** - * Is the saving deferred? This increases the response time. - */ - private boolean deferredExpressionStorage = false; - protected void onInit() { try { Content2BeanUtil.setProperties(this, getConfigNode()); @@ -92,7 +87,7 @@ protected void startEngine() { try { log.info("Starting openwfe engine"); - wfEngine = new JCRPersistedEngine(deferredExpressionStorage); + wfEngine = new JCRPersistedEngine(); wfEngine.registerParticipant(new MgnlParticipant(WorkflowConstants.PARTICIPANT_PREFIX_USER+".*")); wfEngine.registerParticipant(new MgnlParticipant(WorkflowConstants.PARTICIPANT_PREFIX_GROUP+".*")); wfEngine.registerParticipant(new MgnlParticipant(WorkflowConstants.PARTICIPANT_PREFIX_ROLE+".*")); @@ -162,14 +157,4 @@ this.backupWorkItems = backupWorkItems; } - - public boolean isDeferredExpressionStorage() { - return this.deferredExpressionStorage; - } - - - public void setDeferredExpressionStorage(boolean deferredExpressionStorage) { - this.deferredExpressionStorage = deferredExpressionStorage; - } - } Index: magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/MgnlParticipant.java =================================================================== --- magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/MgnlParticipant.java (revision 15750) +++ magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/MgnlParticipant.java (working copy) @@ -33,6 +33,8 @@ */ package info.magnolia.module.workflow; +import info.magnolia.cms.util.ExceptionHandlingOperation; +import info.magnolia.cms.util.SystemContextOperationUtil; import info.magnolia.commands.CommandsManager; import info.magnolia.context.Context; import info.magnolia.context.MgnlContext; @@ -85,9 +87,7 @@ // remove workitem from inbox WorkflowUtil.getWorkItemStore().removeWorkItem(cancelItem.getId()); } - // else { - // // ignore - // } + MgnlContext.release(); } /** @@ -151,45 +151,23 @@ } } else { - StoreWorkItemSystemContextOperation storeWokItemOperation = new StoreWorkItemSystemContextOperation(wi); - MgnlContext.doInSystemContext(storeWokItemOperation, true); - if(storeWokItemOperation.hasException()){ - throw storeWokItemOperation.getException(); - } + SystemContextOperationUtil.execute(new StoreWorkItemSystemContextOperation(wi), true); } log.debug("leave consume().."); } - private final class StoreWorkItemSystemContextOperation implements MgnlContext.SystemContextOperation { + private static final class StoreWorkItemSystemContextOperation extends ExceptionHandlingOperation { private final WorkItem wi; - private StoreException exception; - private StoreWorkItemSystemContextOperation(WorkItem wi) { this.wi = wi; } - public void exec() { - try { - WorkflowUtil.getWorkItemStore().storeWorkItem(StringUtils.EMPTY, (InFlowWorkItem) this.wi); - } - catch (StoreException e) { - this.exception = e; - } + protected void onExec() throws Exception { + WorkflowUtil.getWorkItemStore().storeWorkItem(StringUtils.EMPTY, (InFlowWorkItem) this.wi); } - - public StoreException getException() { - return this.exception; - } - - public boolean hasException(){ - return this.getException() != null; - } - } - - } Index: magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/HierarchyManagerWrapperDelegator.java =================================================================== --- magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/HierarchyManagerWrapperDelegator.java (revision 15750) +++ magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/HierarchyManagerWrapperDelegator.java (working copy) @@ -1,90 +0,0 @@ -/** - * This file Copyright (c) 2003-2008 Magnolia International - * Ltd. (http://www.magnolia.info). All rights reserved. - * - * - * This file is dual-licensed under both the Magnolia - * Network Agreement and the GNU General Public License. - * You may elect to use one or the other of these licenses. - * - * This file is distributed in the hope that it will be - * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. - * Redistribution, except as permitted by whichever of the GPL - * or MNA you select, is prohibited. - * - * 1. For the GPL license (GPL), you can redistribute and/or - * modify this file under the terms of the GNU General - * Public License, Version 3, as published by the Free Software - * Foundation. You should have received a copy of the GNU - * General Public License, Version 3 along with this program; - * if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * 2. For the Magnolia Network Agreement (MNA), this file - * and the accompanying materials are made available under the - * terms of the MNA which accompanies this distribution, and - * is available at http://www.magnolia.info/mna.html - * - * Any modifications to this file must keep this entire header - * intact. - * - */ -package info.magnolia.module.workflow.jcr; - -import info.magnolia.cms.core.Content; -import info.magnolia.cms.core.HierarchyManager; -import info.magnolia.cms.core.ItemType; -import info.magnolia.cms.util.ContentUtil; -import info.magnolia.context.LifeTimeJCRSessionUtil; - -import javax.jcr.RepositoryException; - -/** - * A basic HierarchyManagerWrapper that just delegates all calls to the HierarchyManager - * retrieved by getHierarchyManager(). - * - * @author gjoseph - * @version $Revision: $ ($Author: $) - */ -public class HierarchyManagerWrapperDelegator implements HierarchyManagerWrapper { - private final String workspaceName; - - public HierarchyManagerWrapperDelegator(String workspaceName) { - this.workspaceName = workspaceName; - } - - public void save() throws RepositoryException { - getHierarchyManager().save(); - } - - public boolean isExist(String path) { - return getHierarchyManager().isExist(path); - } - - public Content getContent(String path) throws RepositoryException { - return getHierarchyManager().getContent(path); - } - - public Content createPath(String path, ItemType itemType) throws RepositoryException { - return ContentUtil.createPath(getHierarchyManager(), path, itemType); - } - - public void delete(String path) throws RepositoryException { - getHierarchyManager().delete(path); - } - - public void moveTo(String path, String to) throws RepositoryException { - getHierarchyManager().moveTo(path, to); - - } - - protected HierarchyManager getHierarchyManager() { - return LifeTimeJCRSessionUtil.getHierarchyManager(workspaceName); - } - - protected String getWorkspaceName() { - return workspaceName; - } -} Index: magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/JCRPersistedEngine.java =================================================================== --- magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/JCRPersistedEngine.java (revision 15750) +++ magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/JCRPersistedEngine.java (working copy) @@ -56,19 +56,19 @@ private final JCRExpressionStore eStore; - public JCRPersistedEngine(final boolean storageDeferred) throws ServiceException { - this(WorkflowConstants.ENGINE_NAME, true, storageDeferred); + public JCRPersistedEngine() throws ServiceException { + this(WorkflowConstants.ENGINE_NAME, true); } /** * Instantiates a JCR persisted engine with the given name */ - public JCRPersistedEngine(final String engineName, final boolean cached, final boolean storageDeferred) throws ServiceException { + public JCRPersistedEngine(final String engineName, final boolean cached) throws ServiceException { super(engineName, cached); super.setDaemon(true); // create expression store and add it to context - this.eStore = new JCRExpressionStore(storageDeferred); + this.eStore = new JCRExpressionStore(); this.eStore.init(Definitions.S_EXPRESSION_STORE, getContext(), Collections.EMPTY_MAP); Index: magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/HierarchyManagerWrapper.java =================================================================== --- magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/HierarchyManagerWrapper.java (revision 15750) +++ magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/HierarchyManagerWrapper.java (working copy) @@ -1,58 +0,0 @@ -/** - * This file Copyright (c) 2003-2008 Magnolia International - * Ltd. (http://www.magnolia.info). All rights reserved. - * - * - * This file is dual-licensed under both the Magnolia - * Network Agreement and the GNU General Public License. - * You may elect to use one or the other of these licenses. - * - * This file is distributed in the hope that it will be - * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. - * Redistribution, except as permitted by whichever of the GPL - * or MNA you select, is prohibited. - * - * 1. For the GPL license (GPL), you can redistribute and/or - * modify this file under the terms of the GNU General - * Public License, Version 3, as published by the Free Software - * Foundation. You should have received a copy of the GNU - * General Public License, Version 3 along with this program; - * if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * 2. For the Magnolia Network Agreement (MNA), this file - * and the accompanying materials are made available under the - * terms of the MNA which accompanies this distribution, and - * is available at http://www.magnolia.info/mna.html - * - * Any modifications to this file must keep this entire header - * intact. - * - */ -package info.magnolia.module.workflow.jcr; - -import info.magnolia.cms.core.Content; -import info.magnolia.cms.core.ItemType; - -import javax.jcr.RepositoryException; - -/** - * @author gjoseph - * @version $Revision: $ ($Author: $) - */ -public interface HierarchyManagerWrapper { - - void save() throws RepositoryException; - - boolean isExist(String path); - - Content getContent(String path) throws RepositoryException; - - Content createPath(String path, ItemType itemType) throws RepositoryException; - - void delete(String path) throws RepositoryException; - - void moveTo(String path, String to) throws RepositoryException; -} Index: magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/HierarchyManagerDeferredSaver.java =================================================================== --- magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/HierarchyManagerDeferredSaver.java (revision 15750) +++ magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/HierarchyManagerDeferredSaver.java (working copy) @@ -1,111 +0,0 @@ -/** - * This file Copyright (c) 2003-2008 Magnolia International - * Ltd. (http://www.magnolia.info). All rights reserved. - * - * - * This file is dual-licensed under both the Magnolia - * Network Agreement and the GNU General Public License. - * You may elect to use one or the other of these licenses. - * - * This file is distributed in the hope that it will be - * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. - * Redistribution, except as permitted by whichever of the GPL - * or MNA you select, is prohibited. - * - * 1. For the GPL license (GPL), you can redistribute and/or - * modify this file under the terms of the GNU General - * Public License, Version 3, as published by the Free Software - * Foundation. You should have received a copy of the GNU - * General Public License, Version 3 along with this program; - * if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * 2. For the Magnolia Network Agreement (MNA), this file - * and the accompanying materials are made available under the - * terms of the MNA which accompanies this distribution, and - * is available at http://www.magnolia.info/mna.html - * - * Any modifications to this file must keep this entire header - * intact. - * - */ -package info.magnolia.module.workflow.jcr; - -import javax.jcr.RepositoryException; - -/** - * A HierarchyManagerWrapper which defers save() calls to try and increase performance. - * - * TODO : exposing this as a HierarchyManager and delegate all non-save calls would probably be possible if HM was an interface. - * - * @author gjoseph - * @version $Revision: $ ($Author: $) - */ -public class HierarchyManagerDeferredSaver extends HierarchyManagerWrapperDelegator implements Runnable { - private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(HierarchyManagerDeferredSaver.class); - - /** - * A factory method to instanciate a new HierarchyManagerDeferredSaver - * and start it in a new daemon thread. - */ - static HierarchyManagerDeferredSaver startInThread(String workspaceName, long sleepDelayMs, long nopingDelayMs, long maxSaveDelayMs) { - final HierarchyManagerDeferredSaver hmSaver = new HierarchyManagerDeferredSaver(workspaceName, sleepDelayMs, nopingDelayMs, maxSaveDelayMs); - final Thread saverThread = new Thread(hmSaver); - saverThread.setDaemon(true); - saverThread.start(); - return hmSaver; - } - - private final long sleepDelayMs; - private final long nopingDelayMs; // the delay after no ping happened where we need to save - private final long maxSaveDelayMs; // even if we're being pinged constantly, we will save at least once every MAX_SAVE_DELAY_MS - - private long lastSaveTimestamp; - private long lastPingTimestamp; - - HierarchyManagerDeferredSaver(String workspaceName, long sleepDelayMs, long nopingDelayMs, long maxSaveDelayMs) { - super(workspaceName); - this.sleepDelayMs = sleepDelayMs; - this.nopingDelayMs = nopingDelayMs; - this.maxSaveDelayMs = maxSaveDelayMs; - } - - /** - * Ping the saver - telling it there's gonna be something to do. - */ - public void save() { - lastPingTimestamp = System.currentTimeMillis(); - if (lastSaveTimestamp == 0) { // initialize lastSaveTimeStamp on first ping - lastSaveTimestamp = lastPingTimestamp - 1; // stuffToBeSaved must be true - } - } - - public void run() { - while (true) { - try { - Thread.sleep(sleepDelayMs); - final long now = System.currentTimeMillis(); - boolean itemsToBeSaved = lastPingTimestamp > lastSaveTimestamp; - boolean lastPingWasNopingDelayAgo = lastPingTimestamp < now - nopingDelayMs; - boolean lastSaveWasMaxSaveDelayAgo = lastSaveTimestamp < now - maxSaveDelayMs; - // log.debug("[" + getWorkspaceName() + "] : itemsToBeSaved = " + itemsToBeSaved + "; lastPingWasNopingDelayAgo = " + lastPingWasNopingDelayAgo + "; lastSaveWasMaxSaveDelayAgo = " + lastSaveWasMaxSaveDelayAgo); - if (itemsToBeSaved && (lastPingWasNopingDelayAgo || lastSaveWasMaxSaveDelayAgo)) { - try { - synchronized (this) { - log.debug("Will save [" + getWorkspaceName() + "] : itemsToBeSaved = " + itemsToBeSaved + "; lastPingWasNopingDelayAgo = " + lastPingWasNopingDelayAgo + "; lastSaveWasMaxSaveDelayAgo = " + lastSaveWasMaxSaveDelayAgo); - getHierarchyManager().save(); - lastSaveTimestamp = System.currentTimeMillis(); - } - } catch (RepositoryException e) { - throw new RuntimeException(e); // TODO - } - } - - } catch (InterruptedException e) { - } - } - } - -} Index: magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/JCRExpressionStore.java =================================================================== --- magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/JCRExpressionStore.java (revision 15750) +++ magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/JCRExpressionStore.java (working copy) @@ -34,11 +34,18 @@ package info.magnolia.module.workflow.jcr; import info.magnolia.cms.core.Content; +import info.magnolia.cms.core.HierarchyManager; import info.magnolia.cms.core.ItemType; import info.magnolia.cms.core.search.Query; import info.magnolia.cms.core.search.QueryManager; import info.magnolia.cms.core.search.QueryResult; +import info.magnolia.cms.util.ContentUtil; +import info.magnolia.cms.util.DumperUtil; +import info.magnolia.cms.util.ExceptionHandlingOperation; +import info.magnolia.cms.util.SystemContextOperationUtil; +import info.magnolia.context.LifeTimeJCRSessionUtil; import info.magnolia.context.MgnlContext; +import info.magnolia.context.SystemContext; import info.magnolia.module.workflow.WorkflowConstants; import openwfe.org.ApplicationContext; import openwfe.org.ServiceException; @@ -72,23 +79,9 @@ */ public class JCRExpressionStore extends AbstractExpressionStore { private static final Logger log = LoggerFactory.getLogger(JCRExpressionStore.class); - private static final long SLEEP_DELAY_MS = 3 * 1000; - private static final long NOPING_DELAY_MS = 6 * 1000; - private static final long MAX_SAVE_DELAY_MS = 30 * 1000; private static final String ENGINE_ID = "ee"; - private final HierarchyManagerWrapper hmWrapper; - - public JCRExpressionStore(boolean isStorageDeferred) throws ServiceException { - if (isStorageDeferred) { - this.hmWrapper = HierarchyManagerDeferredSaver.startInThread(WorkflowConstants.WORKSPACE_EXPRESSION, SLEEP_DELAY_MS, NOPING_DELAY_MS, MAX_SAVE_DELAY_MS); - } else { - this.hmWrapper = new HierarchyManagerWrapperDelegator(WorkflowConstants.WORKSPACE_EXPRESSION); - } - - } - public void init(final String serviceName, final ApplicationContext context, final Map serviceParams) throws ServiceException { super.init(serviceName, context, serviceParams); } @@ -96,50 +89,60 @@ /** * Stores one expresion */ - public void storeExpression(final FlowExpression fe) throws PoolException { + public synchronized void storeExpression(final FlowExpression fe) throws PoolException { + boolean release = !MgnlContext.hasInstance(); try { - synchronized (hmWrapper) { - final Content cExpression = findExpression(fe); + HierarchyManager hm = getHierarchyManager(); + final Content cExpression = findExpression(fe); - log.debug("storeExpression() handle is " + cExpression.getHandle()); + log.debug("storeExpression() handle is " + cExpression.getHandle()); - // set expressionId as attribte id - ValueFactory vf = cExpression.getJCRNode().getSession().getValueFactory(); - String value = fe.getId().toParseableString(); + // set expressionId as attribte id + ValueFactory vf = cExpression.getJCRNode().getSession().getValueFactory(); + String value = fe.getId().toParseableString(); - cExpression.createNodeData(WorkflowConstants.NODEDATA_ID, vf.createValue(value)); + cExpression.createNodeData(WorkflowConstants.NODEDATA_ID, vf.createValue(value)); - //serializeExpressionWithBeanCoder(ct, fe); - serializeExpressionAsXml(cExpression, fe); + //serializeExpressionWithBeanCoder(ct, fe); + serializeExpressionAsXml(cExpression, fe); - hmWrapper.save(); - } - } catch (final Exception e) { + hm.save(); + } + catch (Exception e) { log.error("storeExpression() store exception failed", e); throw new PoolException("storeExpression() store exception failed", e); } + finally{ + if(release){ + MgnlContext.release(); + } + } } /** * Removes the expression from the JCR storage. */ - public void unstoreExpression(final FlowExpression fe) throws PoolException { + public synchronized void unstoreExpression(final FlowExpression fe) throws PoolException { + boolean release = !MgnlContext.hasInstance(); try { - synchronized (hmWrapper) { - final Content cExpression = findExpression(fe); + final Content cExpression = findExpression(fe); - if (cExpression != null) { - // TODO : we could delete this node's parent's parent here. find a good/safe way to do this, for a cleaner repository. - cExpression.delete(); - hmWrapper.save(); - } else { - log.info("unstoreExpression() " + "didn't find content node for fe " + fe.getId().toParseableString()); - } + if (cExpression != null) { + ContentUtil.deleteAndRemoveEmptyParents(cExpression,1); + getHierarchyManager().save(); + } else { + log.info("unstoreExpression() " + "didn't find content node for fe " + fe.getId().toParseableString()); } - } catch (final Exception e) { + } + catch (Exception e) { log.error("unstoreExpression() unstore exception failed", e); throw new PoolException("unstoreExpression() unstore exception failed", e); } + finally{ + if(release){ + MgnlContext.release(); + } + } } /** @@ -203,14 +206,6 @@ c.createNodeData(WorkflowConstants.NODEDATA_VALUE, vf.createValue(s)); } - /* - private void serializeExpressionWithBeanCoder(Content c,FlowExpression fr) throws Exception { - - OwfeJcrBeanCoder coder = new OwfeJcrBeanCoder(null,new MgnlNode(c),WorkflowConstants.NODEDATA_VALUE); - coder.encode(fr); - } - */ - public final String toXPathFriendlyString(final FlowExpressionId fei) { final StringBuffer buffer = new StringBuffer(); final String engineId = fei.getEngineId(); @@ -248,10 +243,11 @@ final String path = toXPathFriendlyString(fei); - if (hmWrapper.isExist(path)) { - return hmWrapper.getContent(path); + final HierarchyManager hm = getHierarchyManager(); + if (hm.isExist(path)) { + return hm.getContent(path); } else { - return hmWrapper.createPath(path, ItemType.EXPRESSION); + return ContentUtil.createPath(hm, path, ItemType.EXPRESSION); } } @@ -267,12 +263,9 @@ return (FlowExpression) XmlBeanCoder.xmlDecode(doc); } - /* - protected FlowExpression deserializeExpressionWithBeanCoder(Content ret) throws Exception { - OwfeJcrBeanCoder coder = new OwfeJcrBeanCoder(null, new MgnlNode(ret.getContent(WorkflowConstants.NODEDATA_VALUE))); - return (FlowExpression)coder.decode(); + protected HierarchyManager getHierarchyManager() { + return MgnlContext.getSystemContext().getHierarchyManager(WorkflowConstants.WORKSPACE_EXPRESSION); } - */ /** * 'lightweight' storeIterator. The previous version were stuffing all @@ -292,7 +285,7 @@ this.assignClass = assignClass; - final QueryManager qm = MgnlContext.getSystemContext().getQueryManager(WorkflowConstants.WORKSPACE_EXPRESSION); + final QueryManager qm = LifeTimeJCRSessionUtil.getQueryManager(WorkflowConstants.WORKSPACE_EXPRESSION); final Query query = qm.createQuery(WorkflowConstants.STORE_ITERATOR_QUERY, Query.SQL); Index: magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/JCRWorkItemStore.java =================================================================== --- magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/JCRWorkItemStore.java (revision 15750) +++ magnolia-module-workflow/src/main/java/info/magnolia/module/workflow/jcr/JCRWorkItemStore.java (working copy) @@ -35,11 +35,13 @@ import info.magnolia.beancoder.MgnlNode; import info.magnolia.cms.core.Content; +import info.magnolia.cms.core.HierarchyManager; import info.magnolia.cms.core.ItemType; import info.magnolia.cms.core.search.Query; import info.magnolia.cms.core.search.QueryManager; import info.magnolia.cms.core.search.QueryResult; import info.magnolia.cms.security.AccessDeniedException; +import info.magnolia.cms.util.ContentUtil; import info.magnolia.context.MgnlContext; import info.magnolia.module.workflow.WorkflowConstants; import info.magnolia.module.workflow.WorkflowModule; @@ -74,17 +76,16 @@ private static final String BACKUP_REL = "backup"; private static final String BACKUP = "/" + BACKUP_REL; - private final HierarchyManagerWrapper hm; private final boolean shouldBackupWorkItems; public JCRWorkItemStore() throws Exception { - this.hm = new HierarchyManagerWrapperDelegator(WorkflowConstants.WORKSPACE_STORE); + HierarchyManager hm = getHierarchyManager(); shouldBackupWorkItems = WorkflowModule.backupWorkitems(); if (shouldBackupWorkItems) { // ensure the backup directory is there. if (!hm.isExist(BACKUP)) { - hm.createPath(BACKUP, ItemType.CONTENT); + ContentUtil.createPath(hm, BACKUP, ItemType.CONTENT); hm.save(); log.info("Created " + BACKUP + " in workflow store."); } @@ -92,33 +93,40 @@ } /** + * @return + */ + protected HierarchyManager getHierarchyManager() { + return MgnlContext.getSystemContext().getHierarchyManager(WorkflowConstants.WORKSPACE_STORE); + } + + /** * Deletes or moves a workItem to the backup folder. */ - public void removeWorkItem(FlowExpressionId fei) throws StoreException { - synchronized (this.hm) { - try { - Content ct = getWorkItemById(fei); - if (ct != null) { - // TODO : this behaviour could be hidden/wrapped in a special HierarchyManager - if (!shouldBackupWorkItems) { - ct.delete(); - } else { - final ValueFactory vf = ct.getJCRNode().getSession().getValueFactory(); - ct.setNodeData("isBackup", vf.createValue(true)); - final Content parent = ct.getParent(); - final String pathInBackup = BACKUP + parent.getHandle(); - hm.createPath(pathInBackup, ItemType.WORKITEM); - hm.save(); - hm.moveTo(ct.getHandle(), BACKUP + ct.getHandle()); - // TODO : MAGNOLIA-1225 : we should only save here, once move uses session instead of workspace - } + public synchronized void removeWorkItem(FlowExpressionId fei) throws StoreException { + try { + HierarchyManager hm = getHierarchyManager(); + Content ct = getWorkItemById(fei); + if (ct != null) { + // TODO : this behaviour could be hidden/wrapped in a special HierarchyManager + if (!shouldBackupWorkItems) { + ContentUtil.deleteAndRemoveEmptyParents(ct,1); + } else { + final ValueFactory vf = ct.getJCRNode().getSession().getValueFactory(); + ct.setNodeData("isBackup", vf.createValue(true)); + final Content parent = ct.getParent(); + final String pathInBackup = BACKUP + parent.getHandle(); + ContentUtil.createPath(hm, pathInBackup, ItemType.WORKITEM); hm.save(); - log.debug("work item removed or moved to /backup"); + hm.moveTo(ct.getHandle(), BACKUP + ct.getHandle()); + // TODO : MAGNOLIA-1225 : we should only save here, once move uses session instead of workspace } - } catch (Exception e) { - log.error("exception when unstoring workitem:" + e, e); + hm.save(); + log.debug("work item removed or moved to /backup"); } + + } catch (Exception e) { + log.error("exception when unstoring workitem:" + e, e); } } @@ -184,7 +192,7 @@ public Content getWorkItemById(FlowExpressionId fei) { String path = createPathFromId(fei); try { - return this.hm.getContent(path); + return getHierarchyManager().getContent(path); } catch (Exception e) { log.error("get work item by id failed, path = " + path, e); @@ -202,7 +210,7 @@ if (StringUtils.isNotEmpty(path) && StringUtils.indexOf(path, "/") != 0) { path = "/" + path; } - return this.hm.isExist(path); + return getHierarchyManager().isExist(path); } /** @@ -258,51 +266,49 @@ * @param arg0 TODO : this parameter is not used ... * @param wi the work item to be stored */ - public void storeWorkItem(String arg0, InFlowWorkItem wi) throws StoreException { - synchronized (this.hm) { - try { + public synchronized void storeWorkItem(String arg0, InFlowWorkItem wi) throws StoreException { + try { + HierarchyManager hm = getHierarchyManager(); + // delete it if already exist + if (hasWorkItem(wi.getId())) { + // do not use removeWorkItem() since it persist changes immedietely + hm.delete(createPathFromId(wi.getId())); + } - // delete it if already exist - if (hasWorkItem(wi.getId())) { - // do not use removeWorkItem() since it persist changes immedietely - this.hm.delete(createPathFromId(wi.getId())); - } + // create path from work item id + String path = createPathFromId(wi.getId()); + if (log.isDebugEnabled()) { + log.debug("storing workitem with path = " + path); + } - // create path from work item id - String path = createPathFromId(wi.getId()); - if (log.isDebugEnabled()) { - log.debug("storing workitem with path = " + path); - } + Content newc = ContentUtil.createPath(hm,path, ItemType.WORKITEM); - Content newc = hm.createPath(path, ItemType.WORKITEM); + ValueFactory vf = newc.getJCRNode().getSession().getValueFactory(); + String sId = wi.getLastExpressionId().toParseableString(); - ValueFactory vf = newc.getJCRNode().getSession().getValueFactory(); - String sId = wi.getLastExpressionId().toParseableString(); + newc.createNodeData(WorkflowConstants.NODEDATA_ID, vf.createValue(sId)); + newc.createNodeData(WorkflowConstants.NODEDATA_PARTICIPANT, vf.createValue(wi.getParticipantName())); - newc.createNodeData(WorkflowConstants.NODEDATA_ID, vf.createValue(sId)); - newc.createNodeData(WorkflowConstants.NODEDATA_PARTICIPANT, vf.createValue(wi.getParticipantName())); - - StringAttribute assignTo = (StringAttribute) wi.getAttribute(WorkflowConstants.ATTRIBUTE_ASSIGN_TO); - if (assignTo != null) { - String s = assignTo.toString(); - if (s.length() > 0) { - newc.createNodeData(WorkflowConstants.ATTRIBUTE_ASSIGN_TO, vf.createValue(s)); - } + StringAttribute assignTo = (StringAttribute) wi.getAttribute(WorkflowConstants.ATTRIBUTE_ASSIGN_TO); + if (assignTo != null) { + String s = assignTo.toString(); + if (s.length() > 0) { + newc.createNodeData(WorkflowConstants.ATTRIBUTE_ASSIGN_TO, vf.createValue(s)); } + } - // convert to xml string - encodeWorkItemToNode(wi, newc); - hm.save(); + // convert to xml string + encodeWorkItemToNode(wi, newc); + hm.save(); - if (log.isDebugEnabled()) { - log.debug("store work item ok. "); - } + if (log.isDebugEnabled()) { + log.debug("store work item ok. "); } - catch (Exception e) { - log.error("store work item failed", e); - throw new StoreException(e.toString()); - } } + catch (Exception e) { + log.error("store work item failed", e); + throw new StoreException(e.toString()); + } } protected void encodeWorkItemToNode(InFlowWorkItem wi, Content newc) throws BeanCoderException { @@ -339,7 +345,7 @@ // check for stale data. try { - if (!hm.isExist(ct.getHandle())) { + if (!getHierarchyManager().isExist(ct.getHandle())) { if (log.isDebugEnabled()) { log.debug(ct.getHandle() + " does not exist anymore."); } Index: magnolia-empty-webapp/pom.xml =================================================================== --- magnolia-empty-webapp/pom.xml (revision 15750) +++ magnolia-empty-webapp/pom.xml (working copy) @@ -56,6 +56,12 @@ info.magnolia + magnolia-module-workflow + 3.5.9-SNAPSHOT + + + + info.magnolia magnolia-taglib-cms 3.5.9-SNAPSHOT Index: magnolia-core/src/test/java/info/magnolia/test/mock/MockUtil.java =================================================================== --- magnolia-core/src/test/java/info/magnolia/test/mock/MockUtil.java (revision 15750) +++ magnolia-core/src/test/java/info/magnolia/test/mock/MockUtil.java (working copy) @@ -131,10 +131,10 @@ MgnlContext.setInstance(ctx); // and system context as well FactoryUtil.setInstanceFactory(SystemContext.class, new FactoryUtil.InstanceFactory(){ - public Object newInstance() { - return ctx; - } - }); + public Object newInstance() { + return ctx; + } + }); return ctx; } @@ -197,7 +197,13 @@ String orgKey = (String) o; String valueStr = properties.getProperty(orgKey); - String key = StringUtils.replace(orgKey, "/", "."); + //if this is a node definition (no property) + String key = orgKey; + if(StringUtils.isEmpty(valueStr) && !key.contains(".") && !key.contains("@")){ + key += "@type"; + valueStr = "nt:base"; + } + key = StringUtils.replace(key, "/", "."); key = StringUtils.removeStart(key, "."); // guarantee a dot in front of @ to make it a property key = StringUtils.replace(StringUtils.replace(key, "@", ".@"), "..@", ".@"); Index: magnolia-core/src/test/java/info/magnolia/test/mock/MockUtilTest.java =================================================================== --- magnolia-core/src/test/java/info/magnolia/test/mock/MockUtilTest.java (revision 15750) +++ magnolia-core/src/test/java/info/magnolia/test/mock/MockUtilTest.java (working copy) @@ -161,7 +161,7 @@ HierarchyManager hm = MockUtil.createHierarchyManager(content); assertEquals("one", hm.getContent("/node1/sub1").getNodeData("prop1").getString()); assertEquals(0, hm.getContent("/node2/sub2").getNodeDataCollection().size()); - // assertEquals(0, hm.getContent("/node3/sub3").getNodeDataCollection().size()); + assertEquals(0, hm.getContent("/node3/sub3").getNodeDataCollection().size()); assertEquals(0, hm.getContent("/node4").getNodeDataCollection().size()); } Index: magnolia-core/src/test/java/info/magnolia/cms/util/ContentUtilTest.java =================================================================== --- magnolia-core/src/test/java/info/magnolia/cms/util/ContentUtilTest.java (revision 15750) +++ magnolia-core/src/test/java/info/magnolia/cms/util/ContentUtilTest.java (working copy) @@ -34,12 +34,16 @@ package info.magnolia.cms.util; import info.magnolia.cms.core.Content; +import info.magnolia.cms.core.HierarchyManager; import info.magnolia.cms.core.ItemType; import info.magnolia.test.mock.MockContent; +import info.magnolia.test.mock.MockUtil; import junit.framework.TestCase; import static org.easymock.EasyMock.*; import javax.jcr.RepositoryException; + +import java.io.IOException; import java.util.Arrays; import java.util.List; @@ -90,6 +94,40 @@ verify(visitor); } + public void testDeleteAndRemoveParentsIfAnOtherChild() throws IOException, RepositoryException{ + String content = "/node1/child1\n" + + "/node1/child2\n"; + + HierarchyManager hm = MockUtil.createHierarchyManager(content); + + Content child1 = hm.getContent("/node1/child1"); + ContentUtil.deleteAndRemoveEmptyParents(child1); + assertTrue("node1 should not be deleted because it has children", hm.isExist("/node1")); + + } + + public void testDeleteAndRemoveParentsIfNoOtherChild() throws IOException, RepositoryException{ + String content = "/node1/child1"; + HierarchyManager hm = MockUtil.createHierarchyManager(content); + + Content child1 = hm.getContent("/node1/child1"); + ContentUtil.deleteAndRemoveEmptyParents(child1); + assertTrue("node1 must be deleted because it has no children", !hm.isExist("/node1")); + } + + public void testDeleteAndRemoveParentsWithLevel() throws IOException, RepositoryException{ + String content = "/node1/child1/subchild1"; + + HierarchyManager hm = MockUtil.createHierarchyManager(content); + + Content subchild1 = hm.getContent("/node1/child1/subchild1"); + ContentUtil.deleteAndRemoveEmptyParents(subchild1,1); + + assertTrue("child1 must be deleted because it has no children", !hm.isExist("/node1/child1")); + assertTrue("node1 must existe because the level was defined", hm.isExist("/node1")); + + } + private final static class ContentTypeRejector implements Content.ContentFilter { private final List rejectedTypes; @@ -106,4 +144,6 @@ } } + + } Index: magnolia-core/src/main/java/info/magnolia/cms/util/ContentUtil.java =================================================================== --- magnolia-core/src/main/java/info/magnolia/cms/util/ContentUtil.java (revision 15750) +++ magnolia-core/src/main/java/info/magnolia/cms/util/ContentUtil.java (working copy) @@ -500,4 +500,21 @@ return path; } + public static void deleteAndRemoveEmptyParents(Content node) throws PathNotFoundException, RepositoryException, + AccessDeniedException { + deleteAndRemoveEmptyParents(node, 0); + } + + public static void deleteAndRemoveEmptyParents(Content node, int level) throws PathNotFoundException, RepositoryException, + AccessDeniedException { + Content parent = null; + if(node.getLevel() != 0){ + parent = node.getParent(); + } + node.delete(); + if(parent != null && parent.getLevel()>level && parent.getChildren(ContentUtil.EXCLUDE_META_DATA_CONTENT_FILTER).size()==0){ + deleteAndRemoveEmptyParents(parent, level); + } + } + } Index: magnolia-core/src/main/java/info/magnolia/cms/util/ExceptionHandlingOperation.java =================================================================== --- magnolia-core/src/main/java/info/magnolia/cms/util/ExceptionHandlingOperation.java (revision 0) +++ magnolia-core/src/main/java/info/magnolia/cms/util/ExceptionHandlingOperation.java (revision 0) @@ -0,0 +1,61 @@ +/** + * This file Copyright (c) 2008 Magnolia International + * Ltd. (http://www.magnolia.info). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia.info/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.cms.util; + +import info.magnolia.context.MgnlContext.SystemContextOperation; + +public abstract class ExceptionHandlingOperation implements SystemContextOperation { + + private Exception exception; + + public void exec() { + try { + onExec(); + } + catch (Exception e) { + this.exception = e; + } + } + + abstract protected void onExec() throws Exception; + + public Exception getException() { + return this.exception; + } + + public boolean hasException(){ + return this.getException() != null; + } + +} \ No newline at end of file Property changes on: magnolia-core/src/main/java/info/magnolia/cms/util/ExceptionHandlingOperation.java ___________________________________________________________________ Name: svn:keywords + Author Revision Id Name: svn:eol-style + native Index: magnolia-core/src/main/java/info/magnolia/cms/util/SystemContextOperationUtil.java =================================================================== --- magnolia-core/src/main/java/info/magnolia/cms/util/SystemContextOperationUtil.java (revision 0) +++ magnolia-core/src/main/java/info/magnolia/cms/util/SystemContextOperationUtil.java (revision 0) @@ -0,0 +1,99 @@ +/** + * This file Copyright (c) 2008 Magnolia International + * Ltd. (http://www.magnolia.info). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia.info/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.cms.util; + +import java.lang.reflect.Constructor; +import info.magnolia.context.MgnlContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * @author pbracher + * @version $Id$ + * + */ +public class SystemContextOperationUtil { + + /** + * Logger. + */ + private static Logger log = LoggerFactory.getLogger(SystemContextOperationUtil.class); + + public static void execute(final ExceptionHandlingOperation op) throws Exception { + execute(op, false, false, null, null); + } + + public static void execute(final ExceptionHandlingOperation op, boolean release) throws Exception { + execute(op, release, false, null, null); + } + + public static void execute(final ExceptionHandlingOperation op, boolean release, boolean doLog) throws Exception { + execute(op, release, doLog, null, null); + } + + public static void execute(final ExceptionHandlingOperation op, boolean release, boolean doLog, String exceptionMsg) throws Exception { + execute(op, release, doLog, exceptionMsg, null); + } + + public static void execute(final ExceptionHandlingOperation op, boolean release, boolean doLog, String exceptionMsg, Class exeptionClass) throws Exception { + MgnlContext.doInSystemContext(op, release); + + if(op.hasException()){ + if(exceptionMsg == null){ + exceptionMsg = op.getException().getMessage(); + } + if(doLog){ + log.error(exceptionMsg, op.getException()); + } + // wrap the exception so that we don't loose the root stacktrace + Exception exception = new Exception(exceptionMsg, op.getException()); + + if(exeptionClass != null){ + try { + final Constructor constructor = exeptionClass.getConstructor(new Class[] {String.class, Exception.class}); + exception = (Exception) constructor.newInstance(new Object[]{exceptionMsg, op.getException()}); + } + catch (Exception e) { + log.error("can't instantiate an execption of type " + exeptionClass.getName(), e); + } + } + + throw exception; + } + } + + +} Property changes on: magnolia-core/src/main/java/info/magnolia/cms/util/SystemContextOperationUtil.java ___________________________________________________________________ Name: svn:keywords + Author Revision Id Name: svn:eol-style + native Index: magnolia-core/src/main/java/info/magnolia/beancoder/MgnlNode.java =================================================================== --- magnolia-core/src/main/java/info/magnolia/beancoder/MgnlNode.java (revision 15750) +++ magnolia-core/src/main/java/info/magnolia/beancoder/MgnlNode.java (working copy) @@ -258,7 +258,7 @@ */ public Property setProperty(String propertyName, String valueStr, int type) throws JcrException { if (type == PropertyType.NAME) { - log.warn("setProperty(" + propertyName + ", " + valueStr + " with type PropertyType.NAME, will switch to PropertyType.STRING ..."); + log.debug("setProperty(" + propertyName + ", " + valueStr + " with type PropertyType.NAME, will switch to PropertyType.STRING ..."); type = PropertyType.STRING; } Index: magnolia-core/src/main/java/info/magnolia/context/LifeTimeJCRSessionUtil.java =================================================================== --- magnolia-core/src/main/java/info/magnolia/context/LifeTimeJCRSessionUtil.java (revision 15750) +++ magnolia-core/src/main/java/info/magnolia/context/LifeTimeJCRSessionUtil.java (working copy) @@ -35,6 +35,7 @@ import info.magnolia.cms.beans.config.ContentRepository; import info.magnolia.cms.core.HierarchyManager; +import info.magnolia.cms.core.search.QueryManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,4 +77,14 @@ } } + public static QueryManager getQueryManager(String repository) { + if (useSystemContext) { + return MgnlContext.getSystemContext().getQueryManager(repository); + } + else { + // we handle the session + return repositoryStrategy.getQueryManager(repository, ContentRepository.getDefaultWorkspace(repository)); + } + } + } Index: magnolia-core/src/main/java/info/magnolia/commands/impl/LogCommand.java =================================================================== --- magnolia-core/src/main/java/info/magnolia/commands/impl/LogCommand.java (revision 0) +++ magnolia-core/src/main/java/info/magnolia/commands/impl/LogCommand.java (revision 0) @@ -0,0 +1,84 @@ +/** + * This file Copyright (c) 2008 Magnolia International + * Ltd. (http://www.magnolia.info). All rights reserved. + * + * + * This file is dual-licensed under both the Magnolia + * Network Agreement and the GNU General Public License. + * You may elect to use one or the other of these licenses. + * + * This file is distributed in the hope that it will be + * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * Redistribution, except as permitted by whichever of the GPL + * or MNA you select, is prohibited. + * + * 1. For the GPL license (GPL), you can redistribute and/or + * modify this file under the terms of the GNU General + * Public License, Version 3, as published by the Free Software + * Foundation. You should have received a copy of the GNU + * General Public License, Version 3 along with this program; + * if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 2. For the Magnolia Network Agreement (MNA), this file + * and the accompanying materials are made available under the + * terms of the MNA which accompanies this distribution, and + * is available at http://www.magnolia.info/mna.html + * + * Any modifications to this file must keep this entire header + * intact. + * + */ +package info.magnolia.commands.impl; + +import java.util.Date; + +import info.magnolia.commands.MgnlCommand; +import info.magnolia.context.Context; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * @author pbracher + * @version $Id$ + */ +public class LogCommand extends MgnlCommand { + + private String msg; + + private String log = LogCommand.class.getName(); + + public boolean execute(Context ctx) throws Exception { + getLogger().info(getMsg()); + return true; + } + + public String getMsg() { + if(StringUtils.isEmpty(msg)){ + return new Date().toString(); + } + return this.msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getLog() { + return this.log; + } + + public void setLog(String log) { + this.log = log; + } + + protected Logger getLogger() { + return LoggerFactory.getLogger(getLog()); + } + +} Property changes on: magnolia-core/src/main/java/info/magnolia/commands/impl/LogCommand.java ___________________________________________________________________ Name: svn:keywords + Author Revision Id Name: svn:eol-style + native