mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
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:
@@ -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
|
||||||
|
@@ -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());
|
||||||
|
@@ -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())
|
||||||
|
@@ -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
|
||||||
@@ -85,6 +86,7 @@ public class NewUserWizard extends AbstractWizardBean
|
|||||||
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
|
||||||
|
@@ -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,15 +46,16 @@ 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)
|
||||||
{
|
{
|
||||||
this.avmRemote = avmRemote;
|
this.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;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -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)
|
||||||
*/
|
*/
|
||||||
|
@@ -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();" /> *
|
<h:inputText id="email" value="#{NewUserWizard.email}" validator="#{NewUserWizard.validateEmail}" size="35" maxlength="1024" onkeyup="updateButtonState();" onchange="updateButtonState();" /> *
|
||||||
</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>
|
||||||
|
Reference in New Issue
Block a user