diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index 111a847270..dfedf88af4 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -241,6 +241,9 @@ false + + ${db.txn.isolation} + diff --git a/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-2.2-MappedFKIndexes.sql b/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-2.2-MappedFKIndexes.sql index e4078a6fdf..dcc69b3183 100644 --- a/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-2.2-MappedFKIndexes.sql +++ b/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-2.2-MappedFKIndexes.sql @@ -28,8 +28,6 @@ CREATE INDEX fk_alf_autha_ali ON alf_authority_alias (alias_id); CREATE INDEX fk_alf_autha_aut ON alf_authority_alias (auth_id); CREATE INDEX fk_alf_cass_pnode ON alf_child_assoc (parent_node_id); -CREATE INDEX fk_alf_cass_tqn ON alf_child_assoc (type_qname_id); -CREATE INDEX fk_alf_cass_qnns ON alf_child_assoc (qname_ns_id); CREATE INDEX fk_alf_cass_cnode ON alf_child_assoc (child_node_id); -- alf_global_attributes.attribute is declared unique. Indexes may automatically have been created. @@ -42,20 +40,16 @@ CREATE INDEX fk_alf_matt_matt ON alf_map_attribute_entries (map_id); CREATE INDEX fk_alf_matt_att ON alf_map_attribute_entries (attribute_id); CREATE INDEX fk_alf_node_acl ON alf_node (acl_id); -CREATE INDEX fk_alf_node_tqn ON alf_node (type_qname_id); CREATE INDEX fk_alf_node_txn ON alf_node (transaction_id); CREATE INDEX fk_alf_node_store ON alf_node (store_id); CREATE INDEX fk_alf_nasp_n ON alf_node_aspects (node_id); CREATE INDEX fk_alf_nass_snode ON alf_node_assoc (source_node_id); -CREATE INDEX fk_alf_nass_tqn ON alf_node_assoc (type_qname_id); CREATE INDEX fk_alf_nass_tnode ON alf_node_assoc (target_node_id); CREATE INDEX fk_alf_nprop_n ON alf_node_properties (node_id); -CREATE INDEX fk_alf_perm_tqn ON alf_permission (type_qname_id); - CREATE INDEX fk_alf_qname_ns ON alf_qname (ns_id); CREATE INDEX fk_alf_store_root ON alf_store (root_node_id); @@ -80,7 +74,6 @@ CREATE INDEX fk_avm_nprop_n ON avm_node_properties (node_id); CREATE INDEX fk_avm_n_acl ON avm_nodes (acl_id); CREATE INDEX fk_avm_n_store ON avm_nodes (store_new_id); -CREATE INDEX fk_avm_sprop_qname ON avm_store_properties (qname_id); CREATE INDEX fk_avm_sprop_store ON avm_store_properties (avm_store_id); CREATE INDEX fk_avm_s_acl ON avm_stores (acl_id); diff --git a/config/alfresco/domain/transaction.properties b/config/alfresco/domain/transaction.properties index a4fe290b7b..7caefb41f3 100644 --- a/config/alfresco/domain/transaction.properties +++ b/config/alfresco/domain/transaction.properties @@ -8,7 +8,7 @@ server.transaction.mode.readOnly=PROPAGATION_REQUIRED, readOnly server.transaction.mode.default=PROPAGATION_REQUIRED server.transaction.allow-writes=true -server.transaction.max-retries=20 +server.transaction.max-retries=40 server.transaction.min-retry-wait-ms=100 server.transaction.max-retry-wait-ms=2000 server.transaction.wait-increment-ms=100 \ No newline at end of file diff --git a/config/alfresco/extension/custom-repository.properties.sample b/config/alfresco/extension/custom-repository.properties.sample index 4108ca4e86..6e055eca46 100644 --- a/config/alfresco/extension/custom-repository.properties.sample +++ b/config/alfresco/extension/custom-repository.properties.sample @@ -52,6 +52,7 @@ # #db.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver #db.url=jdbc:sqlserver://localhost:1433;databaseName=alfresco +#db.txn.isolation=4096 # The well known RMI registry port is defined in the alfresco-shared.properties file # alfresco.rmi.services.port=50500 diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index ce8d943146..ac613a56fe 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -160,7 +160,8 @@ db.url=jdbc:mysql:///${db.name} db.username=alfresco db.password=alfresco db.pool.initial=10 -db.pool.max=20 +db.pool.max=40 +db.txn.isolation=-1 # Email configuration mail.host= diff --git a/source/java/org/alfresco/repo/activities/feed/AbstractFeedGenerator.java b/source/java/org/alfresco/repo/activities/feed/AbstractFeedGenerator.java index 8fa28170d7..2b13e1b502 100644 --- a/source/java/org/alfresco/repo/activities/feed/AbstractFeedGenerator.java +++ b/source/java/org/alfresco/repo/activities/feed/AbstractFeedGenerator.java @@ -52,7 +52,7 @@ public abstract class AbstractFeedGenerator implements FeedGenerator private RepoCtx ctx = null; - private boolean busy; + private volatile boolean busy; public void setPostDaoService(ActivityPostDaoService postDaoService) { @@ -124,15 +124,13 @@ public abstract class AbstractFeedGenerator implements FeedGenerator return; } - checkProperties(); + busy = true; try { - // run at least one job cycle - boolean moreWork = true; - while (moreWork) - { - moreWork = generate(); - } + checkProperties(); + + // run one job cycle + generate(); } catch (Throwable e) { diff --git a/source/java/org/alfresco/repo/activities/feed/FeedTaskProcessor.java b/source/java/org/alfresco/repo/activities/feed/FeedTaskProcessor.java index 8673ce5579..d191026e2a 100644 --- a/source/java/org/alfresco/repo/activities/feed/FeedTaskProcessor.java +++ b/source/java/org/alfresco/repo/activities/feed/FeedTaskProcessor.java @@ -38,12 +38,14 @@ import java.net.URISyntaxException; import java.net.URL; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import org.alfresco.repo.activities.feed.control.FeedControlDAO; import org.alfresco.repo.activities.post.ActivityPostDAO; @@ -106,6 +108,10 @@ public abstract class FeedTaskProcessor Configuration cfg = getFreemarkerConfiguration(ctx); Map> activityTemplates = new HashMap>(10); + + Map> siteConnectedUsers = new TreeMap>(); + + Map templateCache = new TreeMap(); // for each activity post ... for (ActivityPostDAO activityPost : activityPosts) @@ -192,28 +198,37 @@ public abstract class FeedTaskProcessor model.put("xmldate", new ISO8601DateFormatMethod()); model.put("repoEndPoint", ctx.getRepoEndPoint()); - Set connectedUsers = null; - if ((activityPost.getSiteNetwork() == null) || (activityPost.getSiteNetwork().length() == 0)) + // Get the members of this site + String thisSite = activityPost.getSiteNetwork(); + + // Save hammering the repository by reusing cached site members + Set connectedUsers = siteConnectedUsers.get(thisSite); + if (connectedUsers == null) { - connectedUsers = new HashSet(1); - } - else - { - try + if ((thisSite == null) || (thisSite.length() == 0)) { - // Repository callback to get site members - connectedUsers = getSiteMembers(ctx, activityPost.getSiteNetwork()); + connectedUsers = Collections.singleton(""); // add empty posting userid - to represent site feed ! } - catch(Exception e) + else { - logger.error(">>> Skipping activity post " + activityPost.getId() + " since failed to get site members: " + e); - updatePostStatus(activityPost.getId(), ActivityPostDAO.STATUS.ERROR); - continue; + try + { + // Repository callback to get site members + connectedUsers = getSiteMembers(ctx, thisSite); + connectedUsers.add(""); // add empty posting userid - to represent site feed ! + + // Cache them for future use in this same invocation + siteConnectedUsers.put(thisSite, connectedUsers); + } + catch(Exception e) + { + logger.error(">>> Skipping activity post " + activityPost.getId() + " since failed to get site members: " + e); + updatePostStatus(activityPost.getId(), ActivityPostDAO.STATUS.ERROR); + continue; + } } } - - connectedUsers.add(""); // add empty posting userid - to represent site feed ! - + try { startTransaction(); @@ -272,12 +287,12 @@ public abstract class FeedTaskProcessor model.put("activityData", activityPost.getActivityData()); } - String activitySummary = processFreemarker(fmTemplate, cfg, model); + String activitySummary = processFreemarker(templateCache, fmTemplate, cfg, model); if (! activitySummary.equals("")) { feed.setActivitySummary(activitySummary); feed.setActivitySummaryFormat(formatFound); - feed.setSiteNetwork(activityPost.getSiteNetwork()); + feed.setSiteNetwork(thisSite); feed.setAppTool(activityPost.getAppTool()); feed.setPostDate(activityPost.getPostDate()); feed.setPostId(activityPost.getId()); @@ -502,9 +517,15 @@ public abstract class FeedTaskProcessor return cfg; } - protected String processFreemarker(String fmTemplate, Configuration cfg, Map model) throws IOException, TemplateException, Exception + protected String processFreemarker(Map templateCache, String fmTemplate, Configuration cfg, Map model) throws IOException, TemplateException, Exception { - Template myTemplate = cfg.getTemplate(fmTemplate); + // Save on lots of modification date checking by caching templates locally + Template myTemplate = templateCache.get(fmTemplate); + if (myTemplate == null) + { + myTemplate = cfg.getTemplate(fmTemplate); + templateCache.put(fmTemplate, myTemplate); + } ByteArrayOutputStream bos = new ByteArrayOutputStream(); Writer out = new OutputStreamWriter(bos); diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperTest.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperTest.java index 99cd47df51..cc978379b0 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperTest.java +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperTest.java @@ -5,6 +5,7 @@ import java.util.Date; import java.util.Set; import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.AuditableProperties; import org.alfresco.repo.domain.Node; import org.alfresco.repo.domain.QNameDAO; import org.alfresco.repo.domain.Server; @@ -549,7 +550,9 @@ public class HibernateSessionHelperTest extends BaseSpringTest node.setTypeQNameId(typeQNameId); node.setTransaction(transaction); node.setDeleted(false); - node.getAuditableProperties().setAuditValues("system", new Date(), false); + AuditableProperties ap = new AuditableProperties(); + node.setAuditableProperties(ap); + ap.setAuditValues("system", new Date(), false); getSession().save(node); return node; diff --git a/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java b/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java index 2ec723b4fd..ded2d244b9 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java @@ -82,7 +82,8 @@ public class NodeImpl extends LifecycleAdapter implements Node, Serializable aspects = new HashSet(5); properties = new HashMap(5); - auditableProperties = new AuditableProperties(); + // Note auditableProperties starts null, as hibernate maps a component containing nulls to null and this would + // cause a lot of dirty checks to fail! } /** @@ -355,6 +356,6 @@ public class NodeImpl extends LifecycleAdapter implements Node, Serializable public void setAuditableProperties(AuditableProperties auditableProperties) { - this.auditableProperties = (auditableProperties == null ? new AuditableProperties() : auditableProperties); + this.auditableProperties = auditableProperties; } } diff --git a/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java b/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java index 847c6aa62c..878747b3cf 100644 --- a/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java +++ b/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java @@ -57,6 +57,8 @@ import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.WrapFactory; +import org.mozilla.javascript.WrappedException; +import org.springframework.beans.factory.InitializingBean; import org.springframework.util.FileCopyUtils; /** @@ -64,7 +66,7 @@ import org.springframework.util.FileCopyUtils; * * @author Kevin Roast */ -public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcessor, ScriptResourceLoader +public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcessor, ScriptResourceLoader, InitializingBean { private static final Log logger = LogFactory.getLog(RhinoScriptProcessor.class); @@ -82,6 +84,12 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess /** Store root path to resolve cm:name based scripts path from */ private String storePath; + /** Pre initialized secure scope object. */ + private Scriptable secureScope; + + /** Pre initialized non secure scope object. */ + private Scriptable nonSecureScope; + /** * Set the default store reference * @@ -340,27 +348,12 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess Context cx = Context.enter(); try { - // The easiest way to embed Rhino is just to create a new scope this way whenever - // you need one. However, initStandardObjects is an expensive method to call and it - // allocates a fair amount of memory. + // Create a thread-specific scope from one of the shared scopes. See http://www.mozilla.org/rhino/scopes.html cx.setWrapFactory(wrapFactory); - Scriptable scope; - if (!secure) - { - scope = cx.initStandardObjects(); - // remove security issue related objects - this ensures the script may not access - // unsecure java.* libraries or import any other classes for direct access - only - // the configured root host objects will be available to the script writer - scope.delete("Packages"); - scope.delete("getClass"); - scope.delete("java"); - } - else - { - // allow access to all libraries and objects, including the importer - // @see http://www.mozilla.org/rhino/ScriptingJava.html - scope = new ImporterTopLevel(cx); - } + Scriptable sharedScope = secure ? this.nonSecureScope : this.secureScope; + Scriptable scope = cx.newObject(sharedScope); + scope.setPrototype(sharedScope); + scope.setParentScope(null); // there's always a model, if only to hold the util objects if (model == null) @@ -398,6 +391,15 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess // extract java object result if wrapped by Rhino return valueConverter.convertValueForRepo((Serializable)result); } + catch (WrappedException w) + { + Throwable err = w.getWrappedException(); + if (err instanceof RuntimeException) + { + throw (RuntimeException) err; + } + throw new AlfrescoRuntimeException(err.getMessage(), err); + } catch (Throwable err) { throw new AlfrescoRuntimeException(err.getMessage(), err); @@ -464,4 +466,50 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess return super.wrapAsJavaObject(cx, scope, javaObject, staticType); } } + + + /** + * Pre initializes two scope objects (one secure and one not) with the standard objects preinitialised. This saves + * on very expensive calls to reinitialize a new scope on every web script execution. See + * http://www.mozilla.org/rhino/scopes.html + * + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception + { + // Initialise the secure scope + Context cx = Context.enter(); + try + { + cx.setWrapFactory(wrapFactory); + this.secureScope = cx.initStandardObjects(); + + // remove security issue related objects - this ensures the script may not access + // unsecure java.* libraries or import any other classes for direct access - only + // the configured root host objects will be available to the script writer + this.secureScope.delete("Packages"); + this.secureScope.delete("getClass"); + this.secureScope.delete("java"); + } + finally + { + Context.exit(); + } + + // Initialise the non-secure scope + cx = Context.enter(); + try + { + cx.setWrapFactory(wrapFactory); + + // allow access to all libraries and objects, including the importer + // @see http://www.mozilla.org/rhino/ScriptingJava.html + this.nonSecureScope = new ImporterTopLevel(cx); + + } + finally + { + Context.exit(); + } + } } diff --git a/source/java/org/alfresco/repo/jscript/ScriptNode.java b/source/java/org/alfresco/repo/jscript/ScriptNode.java index 49451d5550..e075161854 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptNode.java +++ b/source/java/org/alfresco/repo/jscript/ScriptNode.java @@ -55,7 +55,6 @@ import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.lock.LockStatus; -import org.alfresco.service.cmr.model.FileExistsException; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.AssociationRef; @@ -348,10 +347,6 @@ public class ScriptNode implements Serializable, Scopeable { this.services.getFileFolderService().rename(this.nodeRef, name); } - catch (FileExistsException e) - { - throw new AlfrescoRuntimeException("Failed to rename node " + nodeRef + " to " + name, e); - } catch (FileNotFoundException e) { throw new AlfrescoRuntimeException("Failed to rename node " + nodeRef + " to " + name, e); diff --git a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java index 7b29611b57..2ad9b88ffd 100644 --- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java @@ -114,6 +114,7 @@ import org.hibernate.ScrollableResults; import org.hibernate.Session; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; +import org.hibernate.exception.ConstraintViolationException; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; @@ -765,7 +766,8 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements { String currentUser = getCurrentUser(); Date currentDate = new Date(); - AuditableProperties auditableProperties = node.getAuditableProperties(); + AuditableProperties auditableProperties = new AuditableProperties(); + node.setAuditableProperties(auditableProperties); auditableProperties.setAuditValues(currentUser, currentDate, false); } } @@ -779,6 +781,11 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements String currentUser = getCurrentUser(); Date currentDate = new Date(); AuditableProperties auditableProperties = node.getAuditableProperties(); + if (auditableProperties == null) + { + auditableProperties = new AuditableProperties(); + node.setAuditableProperties(auditableProperties); + } auditableProperties.setAuditValues(currentUser, currentDate, false); } } @@ -792,6 +799,11 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements String currentUser = getCurrentUser(); Date currentDate = new Date(); AuditableProperties auditableProperties = node.getAuditableProperties(); + if (auditableProperties == null) + { + auditableProperties = new AuditableProperties(); + node.setAuditableProperties(auditableProperties); + } auditableProperties.setAuditValues(currentUser, currentDate, false); } } @@ -810,8 +822,8 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements Node node = null; if (uuid != null) { - // Get any existing Node. A node with this UUID may have existed before, but must be marked - // deleted; otherwise it will be considered live and valid + // Get any existing Node. A node with this UUID may have existed before, but must be marked + // deleted; otherwise it will be considered live and valid node = getNodeOrNull(store, uuid); } else @@ -1025,13 +1037,13 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements { Long nodeTypeQNameId = qnameDAO.getOrCreateQName(nodeTypeQName).getFirst(); if (!nodeTypeQNameId.equals(node.getTypeQNameId())) - { + { node.setTypeQNameId(nodeTypeQNameId); - // We will need to record the change - recordNodeUpdate(node); - } + // We will need to record the change + recordNodeUpdate(node); } } + } public Serializable getNodeProperty(Long nodeId, QName propertyQName) { @@ -1044,7 +1056,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements if (hasNodeAspect(node, ContentModel.ASPECT_AUDITABLE)) { AuditableProperties auditableProperties = node.getAuditableProperties(); - return auditableProperties.getAuditableProperty(propertyQName); + return auditableProperties == null ? null : auditableProperties.getAuditableProperty(propertyQName); } else { @@ -1082,6 +1094,10 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements if (hasNodeAspect(node, ContentModel.ASPECT_AUDITABLE)) { AuditableProperties auditableProperties = node.getAuditableProperties(); + if (auditableProperties == null) + { + auditableProperties = new AuditableProperties(); + } converted.putAll(auditableProperties.getAuditableProperties()); } @@ -1272,14 +1288,14 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements aspectQNames = new HashSet(aspectQNames); // Remove sys:referenceable aspectQNames.remove(ContentModel.ASPECT_REFERENCEABLE); - + // Convert Set aspectQNameIds = qnameDAO.convertQNamesToIds(aspectQNames, true); // Add them Set nodeAspects = node.getAspects(); nodeAspects.addAll(aspectQNameIds); - + // Record change ID recordNodeUpdate(node); } @@ -1300,7 +1316,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements // Remove them Set nodeAspects = node.getAspects(); nodeAspects.removeAll(aspectQNameIds); - + // Record change ID recordNodeUpdate(node); } @@ -1549,16 +1565,16 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements Long parentNodeId, Long childNodeId, boolean isPrimary, - QName assocTypeQName, + final QName assocTypeQName, QName assocQName, String newName) { - Node parentNode = (Node) getSession().get(NodeImpl.class, parentNodeId); + final Node parentNode = (Node) getSession().get(NodeImpl.class, parentNodeId); Node childNode = (Node) getSession().get(NodeImpl.class, childNodeId); final Pair childNameUnique = getChildNameUnique(assocTypeQName, newName); - ChildAssoc assoc = new ChildAssocImpl(); + final ChildAssoc assoc = new ChildAssocImpl(); assoc.setTypeQName(qnameDAO, assocTypeQName); assoc.setChildNodeName(childNameUnique.getFirst()); assoc.setChildNodeNameCrc(childNameUnique.getSecond()); @@ -1567,27 +1583,33 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements assoc.setIndex(-1); // maintain inverse sets assoc.buildAssociation(parentNode, childNode); - // persist it - Long assocId; - try + // Make sure that all changes to the session are persisted so that we know if any + // failures are from the constraint or not + DirtySessionMethodInterceptor.flushSession(getSession(false)); + Long assocId = (Long) getHibernateTemplate().execute(new HibernateCallback() { - assocId = (Long) getHibernateTemplate().save(assoc); - } - catch (Throwable e) - { - // There is already an entity - if (isDebugEnabled) + public Object doInHibernate(Session session) { - logger.debug( - "Duplicate child association detected: \n" + - " Parent Node: " + parentNode.getId() + "\n" + - " Child Name Used: " + childNameUnique); + try + { + Object result = session.save(assoc); + DirtySessionMethodInterceptor.flushSession(session); + return result; + } + catch (ConstraintViolationException e) + { + // There is already an entity + if (isDebugEnabled) + { + logger.debug("Duplicate child association detected: \n" + " Parent Node: " + + parentNode.getId() + "\n" + " Child Name Used: " + childNameUnique, e); + } + throw new DuplicateChildNodeNameException(parentNode.getNodeRef(), assocTypeQName, childNameUnique + .getFirst()); + } } - throw new DuplicateChildNodeNameException( - parentNode.getNodeRef(), - assocTypeQName, - childNameUnique.getFirst()); - } + }); + // Add it to the cache Set oldParentAssocIds = parentAssocsCache.get(childNode.getId()); if (oldParentAssocIds != null) @@ -1629,7 +1651,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements return new Pair(assocId, assoc.getChildAssocRef(qnameDAO)); } - public void setChildNameUnique(final Long childAssocId, String childName) + public void setChildNameUnique(final Long childAssocId, final String childName) { /* * Work out if there has been any change in the name @@ -1648,33 +1670,31 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements childAssoc.setChildNodeName(childNameUnique.getFirst()); childAssoc.setChildNodeNameCrc(childNameUnique.getSecond().longValue()); // Flush again to force a DB constraint here - DirtySessionMethodInterceptor.flushSession(session, true); - // Done - return null; + try + { + DirtySessionMethodInterceptor.flushSession(session, true); + // Done + return null; + } + catch (ConstraintViolationException e) + { + // There is already an entity + if (isDebugEnabled) + { + logger.debug("Duplicate child association detected: \n" + " Parent Node: " + + parentNode.getId() + "\n" + " Child Name Used: " + childNameUnique, e); + } + + throw new DuplicateChildNodeNameException(parentNode.getNodeRef(), childAssoc + .getTypeQName(qnameDAO), childNameUnique.getFirst()); + } } }; + // Make sure that all changes to the session are persisted so that we know if any // failures are from the constraint or not DirtySessionMethodInterceptor.flushSession(getSession(false)); - try - { - getHibernateTemplate().execute(callback); - } - catch (Throwable e) - { - // There is already an entity - if (isDebugEnabled) - { - logger.debug( - "Duplicate child association detected: \n" + - " Parent Node: " + parentNode.getId() + "\n" + - " Child Name Used: " + childNameUnique); - } - throw new DuplicateChildNodeNameException( - parentNode.getNodeRef(), - childAssoc.getTypeQName(qnameDAO), - childNameUnique.getFirst()); - } + getHibernateTemplate().execute(callback); // Done if (isDebugEnabled) @@ -1685,7 +1705,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements " Child Assoc: " + childAssoc); } } - + /** * Apply the cm:name to the child association. If the child name is null then * a GUID is generated as a substitute. @@ -2973,12 +2993,12 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements { Query query = session .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_USERS_WITHOUT_USAGE) - .setString("storeProtocol", storeRef.getProtocol()) - .setString("storeIdentifier", storeRef.getIdentifier()) + .setString("storeProtocol", storeRef.getProtocol()) + .setString("storeIdentifier", storeRef.getIdentifier()) .setParameter("usernamePropQNameID", usernamePropQNamePair.getFirst()) // cm:username .setParameter("sizeCurrentPropQNameID", sizeCurrentPropQNamePair.getFirst()) // cm:sizeCurrent .setParameter("personTypeQNameID", personTypeQNamePair.getFirst()) // cm:person - ; + ; DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.scroll(ScrollMode.FORWARD_ONLY); } @@ -3009,7 +3029,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements // Done } - + public void getUsersWithUsage( final StoreRef storeRef, final ObjectArrayQueryCallback resultsCallback) @@ -3094,7 +3114,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements Map properties = node.getProperties(); for (Map.Entry entry : properties.entrySet()) { - PropertyMapKey propertyKey = entry.getKey(); + PropertyMapKey propertyKey = entry.getKey(); Long propertyQNameId = propertyKey.getQnameId(); QName propertyQName = qnameDAO.getQName(propertyQNameId).getSecond(); NodePropertyValue propertyValue = entry.getValue(); @@ -3190,7 +3210,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements } // Done } - + /* * Queries for transactions */ diff --git a/source/java/org/alfresco/repo/processor/ScriptServiceImpl.java b/source/java/org/alfresco/repo/processor/ScriptServiceImpl.java index 344ba2f7a6..33d0559159 100644 --- a/source/java/org/alfresco/repo/processor/ScriptServiceImpl.java +++ b/source/java/org/alfresco/repo/processor/ScriptServiceImpl.java @@ -113,6 +113,10 @@ public class ScriptServiceImpl implements ScriptService ScriptProcessor scriptProcessor = getScriptProcessor(scriptClasspath); return scriptProcessor.execute(scriptClasspath, model); } + catch (ScriptException err) + { + throw err; + } catch (Throwable err) { throw new ScriptException("Failed to execute script '" + scriptClasspath + "': " + err.getMessage(), err); @@ -140,6 +144,10 @@ public class ScriptServiceImpl implements ScriptService ScriptProcessor scriptProcessor = lookupScriptProcessor(engine); return scriptProcessor.execute(scriptClasspath, model); } + catch (ScriptException err) + { + throw err; + } catch (Throwable err) { throw new ScriptException("Failed to execute script '" + scriptClasspath + "': " + err.getMessage(), err); @@ -167,6 +175,10 @@ public class ScriptServiceImpl implements ScriptService ScriptProcessor scriptProcessor = getScriptProcessor(scriptRef); return scriptProcessor.execute(scriptRef, contentProp, model); } + catch (ScriptException err) + { + throw err; + } catch (Throwable err) { throw new ScriptException("Failed to execute script '" + scriptRef.toString() + "': " + err.getMessage(), err); @@ -194,6 +206,10 @@ public class ScriptServiceImpl implements ScriptService ScriptProcessor scriptProcessor = lookupScriptProcessor(engine); return scriptProcessor.execute(scriptRef, contentProp, model); } + catch (ScriptException err) + { + throw err; + } catch (Throwable err) { throw new ScriptException("Failed to execute script '" + scriptRef.toString() + "': " + err.getMessage(), err); @@ -218,6 +234,10 @@ public class ScriptServiceImpl implements ScriptService ScriptProcessor scriptProcessor = getScriptProcessor(location.toString()); return scriptProcessor.execute(location, model); } + catch (ScriptException err) + { + throw err; + } catch (Throwable err) { throw new ScriptException("Failed to execute script '" + location.toString() + "': " + err.getMessage(), err); @@ -242,6 +262,10 @@ public class ScriptServiceImpl implements ScriptService ScriptProcessor scriptProcessor = lookupScriptProcessor(engine); return scriptProcessor.execute(location, model); } + catch (ScriptException err) + { + throw err; + } catch (Throwable err) { throw new ScriptException("Failed to execute script '" + location.toString() + "': " + err.getMessage(), err); @@ -278,6 +302,10 @@ public class ScriptServiceImpl implements ScriptService ScriptProcessor scriptProcessor = lookupScriptProcessor(engine); return scriptProcessor.executeString(script, model); } + catch (ScriptException err) + { + throw err; + } catch (Throwable err) { throw new ScriptException("Failed to execute supplied script: " + err.getMessage(), err); diff --git a/source/java/org/alfresco/repo/site/script/Site.java b/source/java/org/alfresco/repo/site/script/Site.java index 9d5fa9a02d..382390c61e 100644 --- a/source/java/org/alfresco/repo/site/script/Site.java +++ b/source/java/org/alfresco/repo/site/script/Site.java @@ -69,7 +69,7 @@ public class Site implements Serializable private ScriptableQNameMap customProperties = null; /** Services Registry */ - private ServiceRegistry services; + private ServiceRegistry serviceRegistry; /** Site service */ private SiteService siteService; @@ -87,7 +87,7 @@ public class Site implements Serializable */ /*package*/ Site(SiteInfo siteInfo, ServiceRegistry serviceRegistry, SiteService siteService, Scriptable scope) { - this.services = serviceRegistry; + this.serviceRegistry = serviceRegistry; this.siteService = siteService; this.siteInfo = siteInfo; this.scope = scope; @@ -186,7 +186,7 @@ public class Site implements Serializable ScriptNode node = null; if (this.siteInfo.getNodeRef() != null) { - node = new ScriptNode(this.siteInfo.getNodeRef(), this.services, this.scope); + node = new ScriptNode(this.siteInfo.getNodeRef(), this.serviceRegistry, this.scope); } return node; @@ -336,19 +336,11 @@ public class Site implements Serializable public ScriptNode getContainer(String componentId) { ScriptNode container = null; - try + NodeRef containerNodeRef = this.siteService.getContainer(getShortName(), componentId); + if (containerNodeRef != null) { - NodeRef containerNodeRef = this.siteService.getContainer(getShortName(), componentId); - if (containerNodeRef != null) - { - container = new ScriptNode(containerNodeRef, this.services, this.scope); - } + container = new ScriptNode(containerNodeRef, this.serviceRegistry, this.scope); } - catch(AlfrescoRuntimeException e) - { - // NOTE: not good practice to catch all, but in general we're not throwing exceptions - // into the script layer - } return container; } @@ -385,56 +377,48 @@ public class Site implements Serializable public ScriptNode createContainer(final String componentId, final String folderType, final Object permissions) { ScriptNode container = null; - try + NodeRef containerNodeRef = AuthenticationUtil.runAs(new RunAsWork() { - NodeRef containerNodeRef = AuthenticationUtil.runAs(new RunAsWork() + public NodeRef doWork() throws Exception { - public NodeRef doWork() throws Exception + // Get the container type + QName folderQName = (folderType == null) ? null : QName.createQName(folderType, serviceRegistry.getNamespaceService()); + + // Create the container node + NodeRef containerNodeRef = Site.this.siteService.createContainer(getShortName(), componentId, folderQName, null); + + // Set any permissions that might have been provided for the container + if (permissions != null && permissions instanceof ScriptableObject) { - // Get the container type - QName folderQName = (folderType == null) ? null : QName.createQName(folderType, services.getNamespaceService()); - - // Create the container node - NodeRef containerNodeRef = Site.this.siteService.createContainer(getShortName(), componentId, folderQName, null); - - // Set any permissions that might have been provided for the container - if (permissions != null && permissions instanceof ScriptableObject) + ScriptableObject scriptable = (ScriptableObject)permissions; + Object[] propIds = scriptable.getIds(); + for (int i = 0; i < propIds.length; i++) { - ScriptableObject scriptable = (ScriptableObject)permissions; - Object[] propIds = scriptable.getIds(); - for (int i = 0; i < propIds.length; i++) + // work on each key in turn + Object propId = propIds[i]; + + // we are only interested in keys that are formed of Strings + if (propId instanceof String) { - // work on each key in turn - Object propId = propIds[i]; - - // we are only interested in keys that are formed of Strings - if (propId instanceof String) - { - // get the value out for the specified key - it must be String - final String key = (String)propId; - final Object value = scriptable.get(key, scriptable); - if (value instanceof String) - { - // Set the permission on the container - Site.this.services.getPermissionService().setPermission(containerNodeRef, key, (String)value, true); - } + // get the value out for the specified key - it must be String + final String key = (String)propId; + final Object value = scriptable.get(key, scriptable); + if (value instanceof String) + { + // Set the permission on the container + Site.this.serviceRegistry.getPermissionService().setPermission(containerNodeRef, key, (String)value, true); } } - } - - return containerNodeRef; - } - }, AuthenticationUtil.SYSTEM_USER_NAME); - - // Create the script node for the container - container = new ScriptNode(containerNodeRef, this.services, this.scope); - } - catch(AlfrescoRuntimeException e) - { - // NOTE: not good practice to catch all, but in general we're not throwing exceptions - // into the script layer - } - return container; + } + } + + return containerNodeRef; + } + }, AuthenticationUtil.SYSTEM_USER_NAME); + + // Create the script node for the container + container = new ScriptNode(containerNodeRef, this.serviceRegistry, this.scope); + return container; } /** @@ -445,17 +429,7 @@ public class Site implements Serializable */ public boolean hasContainer(String componentId) { - boolean hasContainer = false; - try - { - hasContainer = this.siteService.hasContainer(getShortName(), componentId); - } - catch(AlfrescoRuntimeException e) - { - // NOTE: not good practice to catch all, but in general we're not throwing exceptions - // into the script layer - } - return hasContainer; + return this.siteService.hasContainer(getShortName(), componentId); } /** @@ -470,7 +444,7 @@ public class Site implements Serializable if (permissions != null && permissions instanceof ScriptableObject) { // Get the permission service - final PermissionService permissionService = this.services.getPermissionService(); + final PermissionService permissionService = this.serviceRegistry.getPermissionService(); if (!permissionService.getInheritParentPermissions(nodeRef)) { @@ -525,7 +499,7 @@ public class Site implements Serializable { final NodeRef nodeRef = node.getNodeRef(); - PermissionService permissionService = services.getPermissionService(); + PermissionService permissionService = serviceRegistry.getPermissionService(); try { // Ensure node isn't inheriting permissions from an ancestor before deleting @@ -562,8 +536,8 @@ public class Site implements Serializable if (this.customProperties == null) { // create the custom properties map - ScriptNode siteNode = new ScriptNode(this.siteInfo.getNodeRef(), this.services); - this.customProperties = new ContentAwareScriptableQNameMap(siteNode, this.services); + ScriptNode siteNode = new ScriptNode(this.siteInfo.getNodeRef(), this.serviceRegistry); + this.customProperties = new ContentAwareScriptableQNameMap(siteNode, this.serviceRegistry); Map props = siteInfo.getCustomProperties(); for (QName qname : props.keySet()) @@ -578,7 +552,7 @@ public class Site implements Serializable // get the type and label information from the dictionary String title = null; String type = null; - PropertyDefinition propDef = this.services.getDictionaryService().getProperty(qname); + PropertyDefinition propDef = this.serviceRegistry.getDictionaryService().getProperty(qname); if (propDef != null) { type = propDef.getDataType().getName().toString();