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
This commit is contained in:
Derek Hulley
2008-09-19 12:51:08 +00:00
parent 1f74c0282c
commit 997e6537aa
7 changed files with 130 additions and 15 deletions

View File

@@ -1430,6 +1430,7 @@ user_properties=User Properties
first_name=First Name first_name=First Name
last_name=Last Name last_name=Last Name
email=Email email=Email
email_format_is_not_valid=Email format is not valid
company_id=Company ID company_id=Company ID
home_space_location=Home Space Location home_space_location=Home Space Location
home_space_name=Home Space Name home_space_name=Home Space Name

View File

@@ -72,6 +72,10 @@ public abstract class BaseDownloadContentServlet extends BaseServlet
{ {
private static final long serialVersionUID = -4558907921887235966L; private static final long serialVersionUID = -4558907921887235966L;
private static final String POWER_POINT_DOCUMENT_MIMETYPE = "application/vnd.powerpoint";
private static final String POWER_POINT_2007_DOCUMENT_MIMETYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
protected static final String MIMETYPE_OCTET_STREAM = "application/octet-stream"; protected static final String MIMETYPE_OCTET_STREAM = "application/octet-stream";
protected static final String MSG_ERROR_CONTENT_MISSING = "error_content_missing"; protected static final String MSG_ERROR_CONTENT_MISSING = "error_content_missing";
@@ -286,6 +290,14 @@ public abstract class BaseDownloadContentServlet extends BaseServlet
} }
} }
} }
// explicitly set the content disposition header if the content is powerpoint
if (!attachment && (mimetype.equals(POWER_POINT_2007_DOCUMENT_MIMETYPE) ||
mimetype.equals(POWER_POINT_DOCUMENT_MIMETYPE)))
{
res.setHeader("Content-Disposition", "attachment");
}
// set mimetype for the content and the character encoding for the stream // set mimetype for the content and the character encoding for the stream
res.setContentType(mimetype); res.setContentType(mimetype);
res.setCharacterEncoding(reader.getEncoding()); res.setCharacterEncoding(reader.getEncoding());

View File

@@ -258,6 +258,7 @@ public class AVMWorkflowUtil extends WorkflowUtil
final HashMap<QName, Object> props = new HashMap<QName, Object>(1, 1.0f); final HashMap<QName, Object> props = new HashMap<QName, Object>(1, 1.0f);
props.put(WCMWorkflowModel.PROP_FROM_PATH, fromPath); props.put(WCMWorkflowModel.PROP_FROM_PATH, fromPath);
query.setProcessCustomProps(props); query.setProcessCustomProps(props);
query.setActive(true);
final List<WorkflowTask> tasks = workflowService.queryTasks(query); final List<WorkflowTask> tasks = workflowService.queryTasks(query);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())

View File

@@ -65,6 +65,7 @@ import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink; import org.alfresco.web.ui.common.component.UIActionLink;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.EmailValidator;
/** /**
* @author Kevin Roast * @author Kevin Roast
@@ -84,7 +85,8 @@ public class NewUserWizard extends AbstractWizardBean
private static final String STEP2_TITLE_ID = "new_user_step2_title"; private static final String STEP2_TITLE_ID = "new_user_step2_title";
private static final String STEP2_DESCRIPTION_ID = "new_user_step2_desc"; private static final String STEP2_DESCRIPTION_ID = "new_user_step2_desc";
private static final String FINISH_INSTRUCTION_ID = "new_user_finish_instruction"; private static final String FINISH_INSTRUCTION_ID = "new_user_finish_instruction";
private static final String ERROR = "error_person"; private static final String ERROR = "error_person";
private static final String MSG_ERROR_MAIL_NOT_VALID = "email_format_is_not_valid";
/** form variables */ /** form variables */
private String firstName = null; private String firstName = null;
@@ -916,6 +918,23 @@ public class NewUserWizard extends AbstractWizardBean
} }
} }
/**
* Validate Email field data is acceptable
*
* @param context
* @param component
* @param value
* @throws ValidatorException
*/
public void validateEmail(FacesContext context, UIComponent component, Object value) throws ValidatorException
{
EmailValidator emailValidator = EmailValidator.getInstance();
if (!emailValidator.isValid((String) value))
{
String err =Application.getMessage(context, MSG_ERROR_MAIL_NOT_VALID);
throw new ValidatorException(new FacesMessage(err));
}
}
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
// Helper methods // Helper methods

View File

@@ -22,20 +22,23 @@
* http://www.alfresco.com/legal/licensing" */ * http://www.alfresco.com/legal/licensing" */
package org.alfresco.web.forms; package org.alfresco.web.forms;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.alfresco.model.WCMAppModel; import org.alfresco.model.WCMAppModel;
import org.alfresco.repo.domain.PropertyValue; import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.remote.AVMRemoteInputStream;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMNotFoundException;
import org.alfresco.service.cmr.remote.AVMRemote; import org.alfresco.service.cmr.remote.AVMRemote;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.w3c.dom.*; import org.w3c.dom.Document;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import javax.xml.parsers.*;
import java.io.*;
import java.util.Map;
import java.util.HashMap;
/** /**
* Common implementation of functions called in the context of FormDataRenderers. * Common implementation of functions called in the context of FormDataRenderers.
@@ -43,14 +46,15 @@ import java.util.HashMap;
* of both the alfresco webapp and the virtualization server. * of both the alfresco webapp and the virtualization server.
* *
* @author Ariel Backenroth * @author Ariel Backenroth
* @author Arseny Kovalchuk (Fix of the bug reported in https://issues.alfresco.com/jira/browse/ETWOONE-241)
*/ */
public class FormDataFunctions public class FormDataFunctions
{ {
private static final Log LOGGER = LogFactory.getLog(FormDataFunctions.class); private static final Log LOGGER = LogFactory.getLog(FormDataFunctions.class);
private static DocumentBuilder documentBuilder;
private final AVMRemote avmRemote; private final AVMRemote avmRemote;
private ThreadLocal<DocumentBuilderFactory> dbf = new ThreadLocal<DocumentBuilderFactory>();
public FormDataFunctions(final AVMRemote avmRemote) public FormDataFunctions(final AVMRemote avmRemote)
{ {
@@ -70,7 +74,7 @@ public class FormDataFunctions
final InputStream istream = this.avmRemote.getFileInputStream(-1, avmPath); final InputStream istream = this.avmRemote.getFileInputStream(-1, avmPath);
try try
{ {
return XMLUtil.parse(istream); return parseXML(istream);
} }
finally finally
{ {
@@ -123,7 +127,8 @@ public class FormDataFunctions
final InputStream istream = this.avmRemote.getFileInputStream(-1, avmPath + '/' + entryName); final InputStream istream = this.avmRemote.getFileInputStream(-1, avmPath + '/' + entryName);
try try
{ {
result.put(entryName, XMLUtil.parse(istream)); // result.put(entryName, XMLUtil.parse(istream));
result.put(entryName, parseXML(istream));
} }
finally finally
{ {
@@ -133,4 +138,33 @@ public class FormDataFunctions
} }
return result; return result;
} }
/*
* We need an internal method for XML parsing with ThreadLocal DocumentBuilderFactory
* to avoid a multithread access to the parser in XMLUtils.
* Fix of the bug reported in https://issues.alfresco.com/jira/browse/ETWOONE-241 reported.
*/
private Document parseXML(InputStream is) throws IOException, SAXException
{
Document result = null;
try
{
DocumentBuilderFactory localDbf = dbf.get();
if (localDbf == null)
{
localDbf = DocumentBuilderFactory.newInstance();
}
localDbf.setNamespaceAware(true);
localDbf.setValidating(false);
dbf.set(localDbf);
DocumentBuilder builder = localDbf.newDocumentBuilder();
result = builder.parse(is);
}
catch (ParserConfigurationException pce)
{
LOGGER.error(pce);
}
return result;
}
} }

View File

@@ -27,6 +27,9 @@ package org.alfresco.web.ui.repo.component.evaluator;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import javax.faces.context.FacesContext; import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding; import javax.faces.el.ValueBinding;
@@ -42,6 +45,8 @@ import org.alfresco.web.ui.common.component.evaluator.BaseEvaluator;
*/ */
public class ActionInstanceEvaluator extends BaseEvaluator public class ActionInstanceEvaluator extends BaseEvaluator
{ {
private static final String EVALUATOR_CACHE = "_alf_evaluator_cache";
/** /**
* Evaluate by executing the specified action instance evaluator. * Evaluate by executing the specified action instance evaluator.
* *
@@ -56,7 +61,7 @@ public class ActionInstanceEvaluator extends BaseEvaluator
final Object obj = this.getValue(); final Object obj = this.getValue();
if (obj instanceof Node) if (obj instanceof Node)
{ {
result = this.getEvaluator().evaluate((Node)obj); result = evaluateCachedResult((Node)obj);
} }
else else
{ {
@@ -87,6 +92,49 @@ public class ActionInstanceEvaluator extends BaseEvaluator
return result; return result;
} }
/**
* To reduce invocations of a particular evaluator for a particular node
* save a cache of evaluator result for a node against the current request.
* Since the same evaluator may get reused several times for multiple actions, but
* in effect execute against the same node instance, this can significantly reduce
* the number of invocations required for a particular evaluator.
*
* @param node Node to evaluate against
*
* @return evaluator result
*/
private boolean evaluateCachedResult(Node node)
{
Boolean result;
ActionEvaluator evaluator = getEvaluator();
String cacheKey = node.getNodeRef().toString() + '_' + evaluator.getClass().getName();
Map<String, Boolean> cache = getEvaluatorResultCache();
result = cache.get(cacheKey);
if (result == null)
{
result = evaluator.evaluate(node);
cache.put(cacheKey, result);
}
return result;
}
/**
* @return the evaluator result cache - tied to the current request
*/
private Map<String, Boolean> getEvaluatorResultCache()
{
FacesContext fc = FacesContext.getCurrentInstance();
Map<String, Boolean> cache = (Map<String, Boolean>)fc.getExternalContext().getRequestMap().get(EVALUATOR_CACHE);
if (cache == null)
{
cache = new HashMap<String, Boolean>(64, 1.0f);
fc.getExternalContext().getRequestMap().put(EVALUATOR_CACHE, cache);
}
return cache;
}
/** /**
* @see javax.faces.component.StateHolder#restoreState(javax.faces.context.FacesContext, java.lang.Object) * @see javax.faces.component.StateHolder#restoreState(javax.faces.context.FacesContext, java.lang.Object)
*/ */

View File

@@ -170,7 +170,7 @@
<tr> <tr>
<td><h:outputText value="#{msg.email}"/>:</td> <td><h:outputText value="#{msg.email}"/>:</td>
<td> <td>
<h:inputText id="email" value="#{NewUserWizard.email}" size="35" maxlength="1024" onkeyup="updateButtonState();" onchange="updateButtonState();" />&nbsp;* <h:inputText id="email" value="#{NewUserWizard.email}" validator="#{NewUserWizard.validateEmail}" size="35" maxlength="1024" onkeyup="updateButtonState();" onchange="updateButtonState();" />&nbsp;*
</td> </td>
</tr> </tr>
@@ -209,7 +209,7 @@
<tr><td class="wizardButtonSpacing"></td></tr> <tr><td class="wizardButtonSpacing"></td></tr>
<tr> <tr>
<td align="center"> <td align="center">
<h:commandButton value="#{msg.cancel_button}" action="#{NewUserWizard.cancel}" styleClass="wizardButton" /> <h:commandButton value="#{msg.cancel_button}" action="#{NewUserWizard.cancel}" styleClass="wizardButton" immediate="true" />
</td> </td>
</tr> </tr>
</table> </table>