From 8fb3a02d1f6f49d03e8784e0cc750eb1f84c8976 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Fri, 19 Sep 2008 12:51:08 +0000 Subject: [PATCH] Merged V2.2 to HEAD 10931: Merged V2.1 to V2.2 9931: Fix for https://issues.alfresco.com/jira/browse/ETWOONE-295 10094: Further fix for ETWOONE-241: SAXException - XML parser apparently is not thread safe 10101: Resolve ACT 1282: wcm workflow falling over on Oracle while hitting in clause limit of 1000 expressions. 10188: https://issues.alfresco.com/jira/browse/ETWOONE-74 (Part 1) 10447: ETWOONE-328: performance improvement added to rule trigger code 10455: Fix for ETWOONE-306. 10292: Fix for ETWOONE-92: If two users update the same contents at the same time, you get InvalidNodeRefException 10293: Fix for ETWOONE-116: Send email action does not handle invalid email address 10294: Fix for ETWOONE-164: when a powerpoint 2007 pptx is stored in alfresco ... 10341: Action Evaluator request level cache git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10934 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../authentication-services-context.xml | 6 + config/alfresco/core-services-context.xml | 75 +++++++- .../action/executer/MailActionExecuter.java | 26 ++- .../alfresco/repo/rule/RuleServiceImpl.java | 3 +- .../org/alfresco/repo/rule/RuleTypeImpl.java | 14 +- .../ADMLuceneIndexerAndSearcherFactory.java | 8 +- .../impl/lucene/ADMLuceneIndexerImpl.java | 12 ++ .../lucene/ADMLuceneNoActionIndexerImpl.java | 100 +++++++++++ ...uceneUnIndexedIndexAndSearcherFactory.java | 44 +++++ .../authentication/AuthenticationTest.java | 167 ++++++++++++++++-- .../InMemoryTicketComponentImpl.java | 116 ++++++++---- .../repo/workflow/jbpm/ForEachFork.java | 8 +- .../repo/workflow/jbpm/JBPMEngine.java | 80 +++++---- 13 files changed, 556 insertions(+), 103 deletions(-) create mode 100644 source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneNoActionIndexerImpl.java create mode 100644 source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneUnIndexedIndexAndSearcherFactory.java diff --git a/config/alfresco/authentication-services-context.xml b/config/alfresco/authentication-services-context.xml index 32fcba35c5..846c2642b6 100644 --- a/config/alfresco/authentication-services-context.xml +++ b/config/alfresco/authentication-services-context.xml @@ -411,6 +411,12 @@ false + + + + + + AFTER_FIXED_TIME diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index bf95720ed0..4ffad67fb3 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -421,6 +421,12 @@ + + + + + + @@ -438,13 +444,17 @@ - - - + + + + + + + @@ -544,6 +554,63 @@ + + + + + + + + + + + + + + + ${dir.indexes} + + + + + + + + + ${lucene.maxAtomicTransformationTime} + + + ${lucene.query.maxClauses} + + + ${lucene.indexer.batchSize} + + + ${dir.indexes.lock} + + + ${lucene.indexer.maxFieldLength} + + + ${lucene.write.lock.timeout} + + + ${lucene.commit.lock.timeout} + + + ${lucene.lock.poll.interval} + + + EXACT_LANGUAGE_AND_ALL + + + EXACT_LANGUAGE_AND_ALL + + + + + - + diff --git a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java index 9be9e5fab5..666b918b19 100644 --- a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java @@ -34,7 +34,6 @@ import java.util.Set; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; -import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.action.ParameterDefinitionImpl; import org.alfresco.repo.template.DateCompareMethod; @@ -54,6 +53,7 @@ import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PersonService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.commons.validator.EmailValidator; import org.springframework.beans.factory.InitializingBean; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; @@ -261,7 +261,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase { NodeRef person = personService.getPerson(authority); String address = (String)nodeService.getProperty(person, ContentModel.PROP_EMAIL); - if (address != null && address.length() != 0) + if (address != null && address.length() != 0 && validateAddress(address)) { recipients.add(address); } @@ -351,6 +351,28 @@ public class MailActionExecuter extends ActionExecuterAbstractBase logger.error("Failed to send email to " + to, e); } } + + /** + * Return true if address has valid format + * @param address + * @return + */ + private boolean validateAddress(String address) + { + boolean result = false; + + EmailValidator emailValidator = EmailValidator.getInstance(); + if (emailValidator.isValid(address)) + { + result = true; + } + else + { + logger.error("Failed to send email to '" + address + "' as the address is incorrectly formatted" ); + } + + return result; + } /** * @param ref The node representing the current document ref diff --git a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java index 2741f2682f..8fa8db6511 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java @@ -538,7 +538,8 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService * @param ruleNodeRef the rule node reference * @return the rule */ - public Rule getRule(NodeRef ruleNodeRef) + @SuppressWarnings("unchecked") + public Rule getRule(NodeRef ruleNodeRef) { // Get the rule properties Map props = this.runtimeNodeService.getProperties(ruleNodeRef); diff --git a/source/java/org/alfresco/repo/rule/RuleTypeImpl.java b/source/java/org/alfresco/repo/rule/RuleTypeImpl.java index a2019c98a8..e235d14c30 100644 --- a/source/java/org/alfresco/repo/rule/RuleTypeImpl.java +++ b/source/java/org/alfresco/repo/rule/RuleTypeImpl.java @@ -129,14 +129,14 @@ public class RuleTypeImpl extends CommonResourceAbstractBase implements RuleType this.nodeService.exists(actionedUponNodeRef) == true && this.nodeService.hasAspect(actionedUponNodeRef, ContentModel.ASPECT_TEMPORARY) == false) { - if (this.ruleService.hasRules(nodeRef) == true) + List rules = this.ruleService.getRules( + nodeRef, + true, + this.name); + + if (rules.size() != 0) { - List rules = this.ruleService.getRules( - nodeRef, - true, - this.name); - - for (Rule rule : rules) + for (Rule rule : rules) { if (logger.isDebugEnabled() == true) { diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerAndSearcherFactory.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerAndSearcherFactory.java index b8a3eeb2f2..25576b16fb 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerAndSearcherFactory.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerAndSearcherFactory.java @@ -42,15 +42,15 @@ import org.alfresco.service.namespace.NamespaceService; */ public class ADMLuceneIndexerAndSearcherFactory extends AbstractLuceneIndexerAndSearcherFactory implements SupportsBackgroundIndexing { - private DictionaryService dictionaryService; + protected DictionaryService dictionaryService; private NamespaceService nameSpaceService; - private NodeService nodeService; + protected NodeService nodeService; - private FullTextSearchIndexer fullTextSearchIndexer; + protected FullTextSearchIndexer fullTextSearchIndexer; - private ContentService contentService; + protected ContentService contentService; /** * Set the dictinary service diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java index bb431efad8..88c97c87e7 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java @@ -393,6 +393,18 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp indexer.initialise(storeRef, deltaId); return indexer; } + + public static ADMLuceneNoActionIndexerImpl getNoActionIndexer(StoreRef storeRef, String deltaId, LuceneConfig config) throws LuceneIndexException + { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("Creating indexer"); + } + ADMLuceneNoActionIndexerImpl indexer = new ADMLuceneNoActionIndexerImpl(); + indexer.setLuceneConfig(config); + indexer.initialise(storeRef, deltaId); + return indexer; + } /* * Transactional support Used by the resource manager for indexers. diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneNoActionIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneNoActionIndexerImpl.java new file mode 100644 index 0000000000..9dca52d6e5 --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneNoActionIndexerImpl.java @@ -0,0 +1,100 @@ +/* + * 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.repo.search.impl.lucene; + +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; + +public class ADMLuceneNoActionIndexerImpl extends ADMLuceneIndexerImpl +{ + + public ADMLuceneNoActionIndexerImpl() + { + // TODO Auto-generated constructor stub + } + + @Override + public void createChildRelationship(ChildAssociationRef relationshipRef) throws LuceneIndexException + { + return; + } + + @Override + public void createNode(ChildAssociationRef relationshipRef) throws LuceneIndexException + { + NodeRef childRef = relationshipRef.getChildRef(); + // If we have the root node we delete all other root nodes first + if ((relationshipRef.getParentRef() == null) && childRef.equals(nodeService.getRootNode(childRef.getStoreRef()))) + { + // do the root node only + super.createNode(relationshipRef); + } + else + { + // Nothing + } + } + + @Override + public void deleteChildRelationship(ChildAssociationRef relationshipRef) throws LuceneIndexException + { + return; + } + + @Override + public void deleteNode(ChildAssociationRef relationshipRef) throws LuceneIndexException + { + NodeRef childRef = relationshipRef.getChildRef(); + // If we have the root node we delete all other root nodes first + if ((relationshipRef.getParentRef() == null) && childRef.equals(nodeService.getRootNode(childRef.getStoreRef()))) + { + // do the root node only + super.deleteNode(relationshipRef); + } + else + { + // Nothing + } + } + + @Override + public void updateChildRelationship(ChildAssociationRef relationshipBeforeRef, ChildAssociationRef relationshipAfterRef) throws LuceneIndexException + { + return; + } + + @Override + public void updateNode(NodeRef nodeRef) throws LuceneIndexException + { + if((nodeService.hasAspect(nodeRef, ContentModel.ASPECT_ROOT) && nodeRef.equals(nodeService.getRootNode(nodeRef.getStoreRef())))) + { + super.updateNode(nodeRef); + } + } + + + +} diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneUnIndexedIndexAndSearcherFactory.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneUnIndexedIndexAndSearcherFactory.java new file mode 100644 index 0000000000..12e9247218 --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneUnIndexedIndexAndSearcherFactory.java @@ -0,0 +1,44 @@ +/* + * 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.repo.search.impl.lucene; + +import org.alfresco.service.cmr.repository.StoreRef; + +public class ADMLuceneUnIndexedIndexAndSearcherFactory extends ADMLuceneIndexerAndSearcherFactory +{ + + @Override + protected LuceneIndexer createIndexer(StoreRef storeRef, String deltaId) + { + ADMLuceneNoActionIndexerImpl indexer = ADMLuceneIndexerImpl.getNoActionIndexer(storeRef, deltaId, this); + indexer.setNodeService(nodeService); + indexer.setDictionaryService(dictionaryService); + // indexer.setLuceneIndexLock(luceneIndexLock); + indexer.setFullTextSearchIndexer(fullTextSearchIndexer); + indexer.setContentService(contentService); + indexer.setMaxAtomicTransformationTime(getMaxTransformationTime()); + return indexer; + } +} diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java index 312a080b11..543c27b379 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationTest.java @@ -48,6 +48,7 @@ import net.sf.acegisecurity.providers.dao.SaltSource; import org.alfresco.model.ContentModel; import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl.ExpiryMode; import org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl.Ticket; import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.ServiceRegistry; @@ -139,8 +140,7 @@ public class AuthenticationTest extends TestCase authenticationManager = (AuthenticationManager) ctx.getBean("authenticationManager"); saltSource = (SaltSource) ctx.getBean("saltSource"); - TransactionService transactionService = (TransactionService) ctx.getBean(ServiceRegistry.TRANSACTION_SERVICE - .getLocalName()); + TransactionService transactionService = (TransactionService) ctx.getBean(ServiceRegistry.TRANSACTION_SERVICE.getLocalName()); userTransaction = transactionService.getUserTransaction(); userTransaction.begin(); @@ -155,8 +155,7 @@ public class AuthenticationTest extends TestCase systemNodeRef = nodeService.createNode(rootNodeRef, children, system, container).getChildRef(); typesNodeRef = nodeService.createNode(systemNodeRef, children, types, container).getChildRef(); Map props = createPersonProperties("Andy"); - personAndyNodeRef = nodeService.createNode(typesNodeRef, children, ContentModel.TYPE_PERSON, container, props) - .getChildRef(); + personAndyNodeRef = nodeService.createNode(typesNodeRef, children, ContentModel.TYPE_PERSON, container, props).getChildRef(); assertNotNull(personAndyNodeRef); deleteAndy(); @@ -270,6 +269,10 @@ public class AuthenticationTest extends TestCase authenticationService.authenticate("Andy_ Woof/Domain", "".toCharArray()); assertEquals("Andy_ Woof/Domain", authenticationService.getCurrentUserName()); + authenticationService.createAuthentication("Andy `\u00ac\u00a6!\u00a3$%^&*()-_=+\t\n\u0000[]{};'#:@~,./<>?\\|", "".toCharArray()); + authenticationService.authenticate("Andy `\u00ac\u00a6!\u00a3$%^&*()-_=+\t\n\u0000[]{};'#:@~,./<>?\\|", "".toCharArray()); + assertEquals("Andy `\u00ac\u00a6!\u00a3$%^&*()-_=+\t\n\u0000[]{};'#:@~,./<>?\\|", authenticationService.getCurrentUserName()); + if (! tenantService.isEnabled()) { authenticationService.createAuthentication("Andy `\u00ac\u00a6!\u00a3$%^&*()-_=+\t\n\u0000[]{};'#:@~,./<>?\\|", "".toCharArray()); @@ -307,8 +310,7 @@ public class AuthenticationTest extends TestCase assertTrue(AndyDetails.isCredentialsNonExpired()); assertTrue(AndyDetails.isEnabled()); assertNotSame("cabbage", AndyDetails.getPassword()); - assertEquals(AndyDetails.getPassword(), passwordEncoder.encodePassword("cabbage", saltSource - .getSalt(AndyDetails))); + assertEquals(AndyDetails.getPassword(), passwordEncoder.encodePassword("cabbage", saltSource.getSalt(AndyDetails))); assertEquals(1, AndyDetails.getAuthorities().length); // Object oldSalt = dao.getSalt(AndyDetails); @@ -465,8 +467,6 @@ public class AuthenticationTest extends TestCase // assertNull(dao.getUserOrNull("Andy")); } - - public void testTicket() { dao.createUser("Andy", "ticket".toCharArray()); @@ -568,6 +568,147 @@ public class AuthenticationTest extends TestCase // assertNull(dao.getUserOrNull("Andy")); } + public void testTicketExpiryMode() + { + InMemoryTicketComponentImpl tc = new InMemoryTicketComponentImpl(); + tc.setOneOff(false); + tc.setTicketsExpire(true); + tc.setValidDuration("P5S"); + tc.setTicketsCache(ticketsCache); + tc.setExpiryMode(ExpiryMode.AFTER_FIXED_TIME.toString()); + + dao.createUser("Andy", "ticket".toCharArray()); + + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Andy", "ticket"); + token.setAuthenticated(false); + + Authentication result = authenticationManager.authenticate(token); + result.setAuthenticated(true); + + String ticket = tc.getNewTicket(getUserName(result)); + tc.validateTicket(ticket); + assertEquals(ticketComponent.getCurrentTicket("Andy"), ticket); + tc.validateTicket(ticket); + assertEquals(ticketComponent.getCurrentTicket("Andy"), ticket); + tc.validateTicket(ticket); + assertEquals(ticketComponent.getCurrentTicket("Andy"), ticket); + + synchronized (this) + { + try + { + wait(10000); + } + catch (InterruptedException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + try + { + tc.validateTicket(ticket); + assertNotNull(null); + } + catch (AuthenticationException e) + { + + } + + try + { + tc.validateTicket(ticket); + assertNotNull(null); + } + catch (AuthenticationException e) + { + + } + + try + { + tc.validateTicket(ticket); + assertNotNull(null); + } + catch (AuthenticationException e) + { + + } + + synchronized (this) + { + try + { + wait(10000); + } + catch (InterruptedException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + try + { + tc.validateTicket(ticket); + assertNotNull(null); + } + catch (AuthenticationException e) + { + + } + + tc.setExpiryMode(ExpiryMode.AFTER_INACTIVITY.toString()); + ticket = tc.getNewTicket(getUserName(result)); + + for (int i = 0; i < 50; i++) + { + synchronized (this) + { + + try + { + wait(100); + } + catch (InterruptedException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + tc.validateTicket(ticket); + + } + } + + synchronized (this) + { + try + { + wait(10000); + } + catch (InterruptedException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + try + { + tc.validateTicket(ticket); + assertNotNull(null); + } + catch (AuthenticationException e) + { + + } + + + dao.deleteUser("Andy"); + // assertNull(dao.getUserOrNull("Andy")); + } + public void testTicketExpires() { InMemoryTicketComponentImpl tc = new InMemoryTicketComponentImpl(); @@ -704,7 +845,7 @@ public class AuthenticationTest extends TestCase // assertNull(dao.getUserOrNull("Andy")); } - + public void testAuthenticationServiceGetNewTicket() { authenticationService.createAuthentication("GUEST", "".toCharArray()); @@ -718,16 +859,16 @@ public class AuthenticationTest extends TestCase // assert the user is authenticated assertEquals("Andy", authenticationService.getCurrentUserName()); - + String ticket1 = authenticationService.getCurrentTicket(); - + authenticationService.authenticate("Andy", "auth1".toCharArray()); // assert the user is authenticated assertEquals("Andy", authenticationService.getCurrentUserName()); - + String ticket2 = authenticationService.getCurrentTicket(); - + assertFalse(ticket1.equals(ticket2)); } diff --git a/source/java/org/alfresco/repo/security/authentication/InMemoryTicketComponentImpl.java b/source/java/org/alfresco/repo/security/authentication/InMemoryTicketComponentImpl.java index ec63924f69..d85cc0ed83 100644 --- a/source/java/org/alfresco/repo/security/authentication/InMemoryTicketComponentImpl.java +++ b/source/java/org/alfresco/repo/security/authentication/InMemoryTicketComponentImpl.java @@ -49,7 +49,7 @@ public class InMemoryTicketComponentImpl implements TicketComponent * Ticket prefix */ public static final String GRANTED_AUTHORITY_TICKET_PREFIX = "TICKET_"; - + private static ThreadLocal currentTicket = new ThreadLocal(); private boolean ticketsExpire; @@ -61,10 +61,11 @@ public class InMemoryTicketComponentImpl implements TicketComponent private String guid; private SimpleCache ticketsCache; // Can't use Ticket as it's private + + private ExpiryMode expiryMode = ExpiryMode.AFTER_FIXED_TIME; /** * IOC constructor - * */ public InMemoryTicketComponentImpl() { @@ -89,7 +90,7 @@ public class InMemoryTicketComponentImpl implements TicketComponent { expiryDate = Duration.add(new Date(), validDuration); } - Ticket ticket = new Ticket(ticketsExpire, expiryDate, userName); + Ticket ticket = new Ticket(ticketsExpire ? expiryMode : ExpiryMode.DO_NOT_EXPIRE, expiryDate, userName, validDuration); ticketsCache.put(ticket.getTicketId(), ticket); String ticketString = GRANTED_AUTHORITY_TICKET_PREFIX + ticket.getTicketId(); currentTicket.set(ticketString); @@ -119,6 +120,7 @@ public class InMemoryTicketComponentImpl implements TicketComponent /** * Helper method to find a ticket + * * @param ticketString * @return - the ticket */ @@ -129,7 +131,8 @@ public class InMemoryTicketComponentImpl implements TicketComponent } /** - * Helper method to extract the ticket id from the ticket string + * Helper method to extract the ticket id from the ticket string + * * @param ticketString * @return - the ticket key */ @@ -271,14 +274,14 @@ public class InMemoryTicketComponentImpl implements TicketComponent /** * Ticket + * * @author andyh - * */ public static class Ticket implements Serializable { private static final long serialVersionUID = -5904510560161261049L; - private boolean expires; + private ExpiryMode expires; private Date expiryDate; @@ -287,18 +290,18 @@ public class InMemoryTicketComponentImpl implements TicketComponent private String ticketId; private String guid; + + private Duration validDuration; - Ticket(boolean expires, Date expiryDate, String userName) + Ticket(ExpiryMode expires, Date expiryDate, String userName, Duration validDuration) { this.expires = expires; this.expiryDate = expiryDate; this.userName = userName; + this.validDuration = validDuration; this.guid = UUIDGenerator.getInstance().generateRandomBasedUUID().toString(); - - String encode = (expires ? "T" : "F") + - ((expiryDate == null) ? new Date().toString(): expiryDate.toString()) + - userName + guid; + String encode = (expires.toString()) + ((expiryDate == null) ? new Date().toString() : expiryDate.toString()) + userName + guid; MessageDigest digester; try { @@ -314,18 +317,18 @@ public class InMemoryTicketComponentImpl implements TicketComponent } catch (NoSuchAlgorithmException e1) { - CRC32 crc = new CRC32(); - crc.update(encode.getBytes()); - byte[] bytes = new byte[4]; - long value = crc.getValue(); - bytes[0] = (byte)(value & 0xFF); - value >>>= 4; - bytes[1] = (byte)(value & 0xFF); - value >>>= 4; - bytes[2] = (byte)(value & 0xFF); - value >>>= 4; - bytes[3] = (byte)(value & 0xFF); - this.ticketId = new String(Hex.encodeHex(bytes)); + CRC32 crc = new CRC32(); + crc.update(encode.getBytes()); + byte[] bytes = new byte[4]; + long value = crc.getValue(); + bytes[0] = (byte) (value & 0xFF); + value >>>= 4; + bytes[1] = (byte) (value & 0xFF); + value >>>= 4; + bytes[2] = (byte) (value & 0xFF); + value >>>= 4; + bytes[3] = (byte) (value & 0xFF); + this.ticketId = new String(Hex.encodeHex(bytes)); } } } @@ -337,14 +340,33 @@ public class InMemoryTicketComponentImpl implements TicketComponent */ boolean hasExpired() { - if (expires && (expiryDate != null) && (expiryDate.compareTo(new Date()) < 0)) - { - return true; - } - else + Date now = new Date(); + switch (expires) { + case AFTER_FIXED_TIME: + if ((expiryDate != null) && (expiryDate.compareTo(now) < 0)) + { + return true; + } + else + { + return false; + } + case AFTER_INACTIVITY: + if ((expiryDate != null) && (expiryDate.compareTo(now) < 0)) + { + return true; + } + else + { + expiryDate = Duration.add(now, validDuration); + return false; + } + case DO_NOT_EXPIRE: + default: return false; } + } public boolean equals(Object o) @@ -358,9 +380,7 @@ public class InMemoryTicketComponentImpl implements TicketComponent return false; } Ticket t = (Ticket) o; - return (this.expires == t.expires) - && this.expiryDate.equals(t.expiryDate) && this.userName.equals(t.userName) - && this.ticketId.equals(t.ticketId); + return (this.expires == t.expires) && this.expiryDate.equals(t.expiryDate) && this.userName.equals(t.userName) && this.ticketId.equals(t.ticketId); } public int hashCode() @@ -368,7 +388,7 @@ public class InMemoryTicketComponentImpl implements TicketComponent return ticketId.hashCode(); } - protected boolean getExpires() + protected ExpiryMode getExpires() { return expires; } @@ -390,10 +410,11 @@ public class InMemoryTicketComponentImpl implements TicketComponent } - /** - * Are tickets single use - * @param oneOff - */ + /** + * Are tickets single use + * + * @param oneOff + */ public void setOneOff(boolean oneOff) { this.oneOff = oneOff; @@ -401,6 +422,7 @@ public class InMemoryTicketComponentImpl implements TicketComponent /** * Do tickets expire + * * @param ticketsExpire */ public void setTicketsExpire(boolean ticketsExpire) @@ -408,8 +430,19 @@ public class InMemoryTicketComponentImpl implements TicketComponent this.ticketsExpire = ticketsExpire; } + + /** + * How should tickets expire. + * @param exipryMode + */ + public void setExpiryMode(String expiryMode) + { + this.expiryMode = ExpiryMode.valueOf(expiryMode); + } + /** * How long are tickets valid (XML duration as a string) + * * @param validDuration */ public void setValidDuration(String validDuration) @@ -430,12 +463,12 @@ public class InMemoryTicketComponentImpl implements TicketComponent public String getCurrentTicket(String userName) { String ticket = currentTicket.get(); - if(ticket == null) + if (ticket == null) { return getNewTicket(userName); } String ticketUser = getAuthorityForTicket(ticket); - if(userName.equals(ticketUser)) + if (userName.equals(ticketUser)) { return ticket; } @@ -449,9 +482,14 @@ public class InMemoryTicketComponentImpl implements TicketComponent { clearCurrentSecurityContext(); } - + public static void clearCurrentSecurityContext() { currentTicket.set(null); } + + public enum ExpiryMode + { + AFTER_INACTIVITY, AFTER_FIXED_TIME, DO_NOT_EXPIRE; + } } diff --git a/source/java/org/alfresco/repo/workflow/jbpm/ForEachFork.java b/source/java/org/alfresco/repo/workflow/jbpm/ForEachFork.java index 9785649447..370fa26988 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/ForEachFork.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/ForEachFork.java @@ -47,6 +47,7 @@ import org.springframework.beans.factory.BeanFactory; public class ForEachFork extends JBPMSpringActionHandler { private static final long serialVersionUID = 4643103713602441652L; + private ServiceRegistry services; private Element foreach; @@ -190,7 +191,7 @@ public class ForEachFork extends JBPMSpringActionHandler protected String getTokenName(Token parent, String transitionName, int loopIndex) { String tokenName = null; - if (transitionName != null) + if (transitionName != null && transitionName.length() > 0) { if (!parent.hasChild(transitionName)) { @@ -210,12 +211,13 @@ public class ForEachFork extends JBPMSpringActionHandler else { // no transition name - int size = ( parent.getChildren()!=null ? parent.getChildren().size()+1 : 1 ); - tokenName = Integer.toString(size); + int size = (parent.getChildren() != null) ? parent.getChildren().size() + 1 : 1; + tokenName = "FOREACHFORK" + Integer.toString(size); } return tokenName + "." + loopIndex; } + /** * Fork Transition */ diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java index 93619a5f9f..b636e1404f 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java @@ -84,6 +84,7 @@ import org.hibernate.Session; import org.hibernate.criterion.Conjunction; import org.hibernate.criterion.Disjunction; import org.hibernate.criterion.Order; +import org.hibernate.criterion.Projections; import org.hibernate.criterion.Property; import org.hibernate.criterion.Restrictions; import org.hibernate.proxy.HibernateProxy; @@ -1302,7 +1303,6 @@ public class JBPMEngine extends BPMEngine */ private Criteria createTaskQueryCriteria(Session session, WorkflowTaskQuery query) { - Criteria process = null; Criteria task = session.createCriteria(TaskInstance.class); // task id @@ -1358,35 +1358,9 @@ public class JBPMEngine extends BPMEngine } } - // process active? - if (query.isActive() != null) - { - process = (process == null) ? task.createCriteria("processInstance") : process; - if (query.isActive()) - { - process.add(Restrictions.isNull("end")); - } - else - { - process.add(Restrictions.isNotNull("end")); - } - } + // process criteria + Criteria process = createProcessCriteria(task, query); - // process id - if (query.getProcessId() != null) - { - process = (process == null) ? task.createCriteria("processInstance") : process; - process.add(Restrictions.eq("id", getJbpmId(query.getProcessId()))); - } - - // process name - if (query.getProcessName() != null) - { - process = (process == null) ? task.createCriteria("processInstance") : process; - Criteria processDef = process.createCriteria("processDefinition"); - processDef.add(Restrictions.eq("name", query.getProcessName().toPrefixString(namespaceService))); - } - // process custom properties if (query.getProcessCustomProps() != null) { @@ -1398,7 +1372,7 @@ public class JBPMEngine extends BPMEngine { // create criteria for process variables Criteria variables = session.createCriteria(VariableInstance.class); - variables.setProjection(Property.forName("processInstance")); + variables.setProjection(Projections.distinct(Property.forName("processInstance"))); Disjunction values = Restrictions.disjunction(); for (Map.Entry prop : props.entrySet()) { @@ -1409,6 +1383,9 @@ public class JBPMEngine extends BPMEngine } variables.add(values); + // note: constrain process variables to same criteria as tasks + createProcessCriteria(variables, query); + // retrieve list of processes matching specified variables List processList = variables.list(); Object[] processIds = null; @@ -1491,6 +1468,49 @@ public class JBPMEngine extends BPMEngine return task; } + /** + * Create process-specific query criteria + * + * @param root + * @param query + * @return + */ + private Criteria createProcessCriteria(Criteria root, WorkflowTaskQuery query) + { + Criteria process = null; + + // process active? + if (query.isActive() != null) + { + process = (process == null) ? root.createCriteria("processInstance") : process; + if (query.isActive()) + { + process.add(Restrictions.isNull("end")); + } + else + { + process.add(Restrictions.isNotNull("end")); + } + } + + // process id + if (query.getProcessId() != null) + { + process = (process == null) ? root.createCriteria("processInstance") : process; + process.add(Restrictions.eq("id", getJbpmId(query.getProcessId()))); + } + + // process name + if (query.getProcessName() != null) + { + process = (process == null) ? root.createCriteria("processInstance") : process; + Criteria processDef = process.createCriteria("processDefinition"); + processDef.add(Restrictions.eq("name", query.getProcessName().toPrefixString(namespaceService))); + } + + return process; + } + /** * Gets a jBPM Task Instance * @param taskSession jBPM task session