Files
alfresco-community-repo/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java
Dave Ward 407e5029cc Merged V4.0-BUG-FIX to HEAD
35224: ALF-12038: Remove trailing JSON comma causing IE7 script error
   35226: ALF-13401 - Saving PowerPoint (mac 2011) via CIFS fails in Mac OS X Lion
   35239: ALF-13409: Further fix to deal with concurrent deletion of a user's site invitations in background
   35245: ALF-13281: Enabled use of autocomplete in IE for forms runtime. This change also allows multiple events to be attached per validation handler
   35253: ALF-13640: Fixed issues with updating task associations + added new test + fixed existing activiti-component-tests
   35271: Translation updates (fixes: ALF-13434) - based on EN r35212. (Dutch still to follow)
   35281: ALF-13227: Fix CSS for Wiki layout of nested lists
   35284: SPANISH: Update from Gloria
   35290: More debug + unit test for mac powerpoint shuffle.
   35291: Added isTemporary method
   35295: ALF-13453	: Remote Code Execution (can create reverse shell).
   - Added ability for XMLUtil parse callers to provide an  optional array of XMLFilterImpl to be used while parsing. 
   -Added secureParseXSL methods that automatically install an XMLFilterImpl that causes a parse failure if any insecure namespaces are encountered.
   35303: Fix for ALF-12444 Node Browser improvement: Index single node and remove single node from indexes
   Part of ALF-13723 SOLR does not include the same query unit tests as lucene
   35305: ALF-13723 SOLR does not include the same query unit tests as lucene
   - test template
   35306: ALF-13723 SOLR does not include the same query unit tests as lucene
   - template for creating test cores
   35323: ALF-13420: Natural sort on form option labels and improvement for CSS - specifically to address transform action in document details.
   35328: ALF-13409: Avoid concurrency issues in unit test tear downs by deleting users before sites. User deletion deletes invitations synchronously. Site deletion deletes invitations concurrently to avoid UI timeouts. The potential to access invitations that are being concurrently deleted still exists, but always did!
   35331: ALF-12126: Ensure that DND upload is disabled for users with only consumer access
   35335: ALF-13708: Merged V3.4-BUG-FIX (3.4.10) to V4.0-BUG-FIX (4.0.2)
      35235: ALF-13673: Amp-loaded duplicated mimetypes should be handled
         - Modified code to allow duplicates to replace parts of the existing mimetype definitions.
         - A warning is logged each time. 
   35336: Spanish and Dutch updates from Gloria, based on EN r35212
   35355: Merged V3.4-BUG-FIX to V4.0-BUG-FIX
      35213: ALF-13686: Merged PATCHES/V3.4.8 to V3.4-BUG-FIX
         34943: ALF-13121: Option to create users either as user1 or user1@domain.com after kerberos authentication
         - New Kerberos subsystem parameter kerberos.authentication.stripUsernameSuffix introduced
         - When true (the default) the @domain sufix will be stripped from Kerberos authenticated usernames in CIFS, SPP, WebDAV and the Web Client
         - When false, should enable a multi-domain customer to use Alfresco (says Mr Gninot)
         35096: ALF-13121: Added missing stripKerberosUsernameSuffix property to sharepointAuthenticationHandler
      35215: ALF-13065: Ensure Wiki new page save button is available on HTML edit action
      35219: ALF-11898: Fixed TinyMCE create HTML content problem for Explorer client
      35261: Translation updates based on EN r35144
      35339: AD 2008 R2, user import via LDAP fails with over 1000 users
      - Problem discovered by Community user with simple workaround
      https://forums.alfresco.com/en/viewtopic.php?f=57&t=43960&sid=5569e5cfbccb3776e11ef4a8e9d50378&p=129664#p129664
      35353: Merged V3.4 to V3.4-BUG-FIX
         35279: ALF-13713: Merged PATCHES/V3.4.8 to V3.4
            35146: Merged DEV to PATCHES/V3.4.8
               35130: ALF-13472: Webdav Does not allow a user to access spaces without read permission on parent spaces
                  Receiving of indirect lock is wrapped into AuthenticationUtil.runAs() invocation to provide a possibility of getting indirect lock for users with appropriate access rights for requested resource
         35280: ALF-10353: Internet Explorer hangs when using the object picker with a larger number of documents
         - reviewed by DD
         35318: ALF-13715: Merged HEAD to V3.4
            31743: Fixed ALF-10157: Web Form Details page for the "Selected Web Content Forms": script error appears on help button click: container.jsp (line 382)
         35341: ALF-13552: Merged V4.0 to V3.4
            35296: ALF-13453: Remote Code Execution (can create reverse shell) - Fix by Shane
            35304: ALF-13453: Extra fix to ensure xalan namespace isn't declared with global scope and can't be hijacked by an input stylesheet
            35307: ALF-13453: Duplicated extra fix to duplicate code in XSLTRenderingEngine!
      35354: Merged V3.4 to V3.4-BUG-FIX (RECORD ONLY)
         35266: Merged V3.4-BUG-FIX to V3.4
            35261: Translation updates based on EN r35144
         35334: Merged V3.4-BUG-FIX to V3.4
            35235: ALF-13673: Amp-loaded duplicated mimetypes should be handled
               - Modified code to allow duplicates to replace parts of the existing mimetype definitions.
               - A warning is logged each time. 
   35356: Merged V4.0 to V4.0-BUG-FIX
      35292: ALF-13721: Merged PATCHES/V4.0.0 to V4.0
         35240: Fix for ALF-13685 The SOLr textContent webscript is not protected by authentication and permission checks.
         35242: Fix for ALF-13685 The SOLr textContent webscript is not protected by authentication and permission checks.
         - /wcs/api/solr and /wcservice/api/solr
      35304: ALF-13453: Extra fix to ensure xalan namespace isn't declared with global scope and can't be hijacked by an input stylesheet
      35307: ALF-13453: Duplicated extra fix to duplicate code in XSLTRenderingEngine!
   35357: Merged V4.0 to V4.0-BUG-FIX (RECORD ONLY)
      35048: Merged V4.0-BUG-FIX to V4.0
         35031: Fix for ALF-12309: Script errors on site pages
      35293: Merged V4.0-BUG-FIX to V4.0
         35172: ALF-13626: category.put.json.ftl has wrong bracket
      35296: Merged V4.0-BUG-FIX to V4.0
         35295: ALF-13453: Remote Code Execution (can create reverse shell)
           - Fix by Shane


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@35359 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2012-04-18 09:42:39 +00:00

776 lines
34 KiB
Java

/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.web.forms;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.model.WCMAppModel;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.template.TemplateNode;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.remote.AVMRemote;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TemplateException;
import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.namespace.DynamicNamespacePrefixResolver;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.XMLUtil;
import org.springframework.extensions.surf.util.URLDecoder;
import org.springframework.extensions.surf.util.URLEncoder;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.wcm.AVMUtil;
import org.alfresco.web.forms.RenderingEngine.TemplateNotFoundException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.jsf.FacesContextUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import freemarker.ext.dom.NodeModel;
import freemarker.template.SimpleDate;
import freemarker.template.SimpleHash;
/**
* Implementation of a rendering engine template
*/
public class RenderingEngineTemplateImpl
implements RenderingEngineTemplate
{
private static final long serialVersionUID = -1656812676972437532L;
private static final Log logger = LogFactory.getLog(RenderingEngineTemplateImpl.class);
private static final DynamicNamespacePrefixResolver namespacePrefixResolver =
new DynamicNamespacePrefixResolver();
static
{
RenderingEngineTemplateImpl.namespacePrefixResolver.registerNamespace(NamespaceService.ALFRESCO_PREFIX,
NamespaceService.ALFRESCO_URI);
}
static final QName PROP_RESOURCE_RESOLVER = QName.createQName(NamespaceService.ALFRESCO_PREFIX,
"resource_resolver",
namespacePrefixResolver);
private static final String WEBSCRIPT_PREFIX = "webscript://";
private final NodeRef nodeRef;
private final NodeRef renditionPropertiesNodeRef;
private transient FormsService formsService;
protected RenderingEngineTemplateImpl(final NodeRef nodeRef,
final NodeRef renditionPropertiesNodeRef,
final FormsService formsService)
{
if (nodeRef == null)
{
throw new NullPointerException();
}
if (renditionPropertiesNodeRef == null)
{
throw new NullPointerException();
}
if (formsService == null)
{
throw new NullPointerException();
}
this.nodeRef = nodeRef;
this.renditionPropertiesNodeRef = renditionPropertiesNodeRef;
this.formsService = formsService;
}
private FormsService getFormsService()
{
if (formsService == null)
{
formsService = (FormsService) FacesHelper.getManagedBean(FacesContext.getCurrentInstance(), "FormsService");
}
return formsService;
}
public String getName()
{
final NodeService nodeService = this.getServiceRegistry().getNodeService();
return (String)nodeService.getProperty(this.nodeRef, ContentModel.PROP_NAME);
}
public String getTitle()
{
final NodeService nodeService = this.getServiceRegistry().getNodeService();
return (String)nodeService.getProperty(this.nodeRef, ContentModel.PROP_TITLE);
}
public String getDescription()
{
final NodeService nodeService = this.getServiceRegistry().getNodeService();
return (String)nodeService.getProperty(this.nodeRef,
ContentModel.PROP_DESCRIPTION);
}
public String getOutputPathPattern()
{
final NodeService nodeService = this.getServiceRegistry().getNodeService();
return (String)nodeService.getProperty(this.renditionPropertiesNodeRef,
WCMAppModel.PROP_OUTPUT_PATH_PATTERN);
}
public NodeRef getNodeRef()
{
return this.nodeRef;
}
public NodeRef getRenditionPropertiesNodeRef()
{
return this.renditionPropertiesNodeRef;
}
public InputStream getInputStream()
throws IOException
{
final ContentService contentService = this.getServiceRegistry().getContentService();
final ContentReader contentReader =
contentService.getReader(this.nodeRef, ContentModel.TYPE_CONTENT);
return contentReader.getContentInputStream();
}
/**
* Provides the rendering engine to use when processing this template.
*
* @return the rendering engine to use when processing this template.
*/
public RenderingEngine getRenderingEngine()
{
NodeService nodeService = this.getServiceRegistry().getNodeService();
String renderingEngineName = null;
try
{
renderingEngineName = (String)nodeService.getProperty(this.nodeRef, WCMAppModel.PROP_PARENT_RENDERING_ENGINE_NAME);
}
catch (InvalidNodeRefException e)
{
logger.warn("RenderingEngineTemplate not found: "+e);
throw new TemplateNotFoundException("RenderingEngineTemplate not found", e);
}
return this.getFormsService().getRenderingEngine(renderingEngineName);
}
/**
* Generates an output path for the rendition by compiling the output path pattern
* as a freemarker template.
*
* @param formInstanceData the form instance data to use for the rendition path.
* @param currentAVMPath the current path in which the form is being created.
* @param name the name which is used in a pattern
*
* @return the output path to use for renditions.
*/
public String getOutputPathForRendition(final FormInstanceData formInstanceData, final String currentAVMPath, final String name)
{
final ServiceRegistry sr = this.getServiceRegistry();
final AVMService avmService = sr.getAVMLockingAwareService();
final String formInstanceDataAVMPath = formInstanceData.getPath();
final Map<String, Object> root = new HashMap<String, Object>();
final String webappName =
(avmService.hasAspect(-1,
AVMUtil.getWebappPath(formInstanceDataAVMPath),
WCMAppModel.ASPECT_WEBAPP)
? AVMUtil.getWebapp(formInstanceDataAVMPath)
: null);
root.put("webapp", webappName);
root.put("name", name);
root.put("extension",
sr.getMimetypeService().getExtension(this.getMimetypeForRendition()));
Document formInstanceDataDocument = null;
try
{
formInstanceDataDocument = formInstanceData.getDocument();
}
catch (Exception e)
{
logger.error(e);
throw new AlfrescoRuntimeException(e.getMessage(), e);
}
final String parentAVMPath = AVMNodeConverter.SplitBase(formInstanceDataAVMPath)[0];
root.put("xml", NodeModel.wrap(formInstanceDataDocument));
root.put("node", new TemplateNode(((FormInstanceDataImpl)formInstanceData).getNodeRef(), sr, null));
root.put("date", new SimpleDate(new Date(), SimpleDate.DATETIME));
root.put("cwd", AVMUtil.getWebappRelativePath(currentAVMPath));
final TemplateService templateService = sr.getTemplateService();
final String outputPathPattern = (FreeMarkerUtil.buildNamespaceDeclaration(formInstanceDataDocument) +
this.getOutputPathPattern());
String result = null;
try
{
result = templateService.processTemplateString("freemarker",
outputPathPattern,
new SimpleHash(root));
}
catch (final TemplateException te)
{
logger.error(te.getMessage(), te);
throw new AlfrescoRuntimeException("Error processing output path pattern " + outputPathPattern +
" for " + name +
" in webapp " + webappName +
":\n" + te.getMessage(),
te);
}
result = AVMUtil.buildPath(parentAVMPath,
result,
AVMUtil.PathRelation.SANDBOX_RELATIVE);
if (logger.isDebugEnabled())
{
logger.debug("processed pattern " + outputPathPattern + " as " + result);
}
return result;
}
public String getMimetypeForRendition()
{
final NodeService nodeService = this.getServiceRegistry().getNodeService();
return (String)nodeService.getProperty(this.renditionPropertiesNodeRef,
WCMAppModel.PROP_MIMETYPE_FOR_RENDITION);
}
public Rendition render(final FormInstanceData formInstanceData,
final String renditionAvmPath)
throws IOException,
SAXException,
RenderingEngine.RenderingException
{
final AVMService avmService = this.getServiceRegistry().getAVMLockingAwareService();
boolean isRegenerate = true;
boolean exists = avmService.lookup(-1, renditionAvmPath) != null;
if (! exists)
{
final String parentAVMPath = AVMNodeConverter.SplitBase(renditionAvmPath)[0];
AVMUtil.makeAllDirectories(parentAVMPath);
avmService.createFile(parentAVMPath,
AVMNodeConverter.SplitBase(renditionAvmPath)[1]).close();
if (logger.isDebugEnabled())
{
logger.debug("Created file node for file: " + renditionAvmPath);
}
avmService.addAspect(renditionAvmPath, ContentModel.ASPECT_TITLED);
avmService.addAspect(renditionAvmPath, WCMAppModel.ASPECT_RENDITION);
isRegenerate = false;
}
else
{
// ETHREEOH-2110
if (! avmService.hasAspect(-1, renditionAvmPath, WCMAppModel.ASPECT_RENDITION))
{
avmService.addAspect(renditionAvmPath, WCMAppModel.ASPECT_RENDITION);
isRegenerate = false;
}
}
final Rendition result = new RenditionImpl(-1,
renditionAvmPath,
this.getFormsService());
this.render(formInstanceData, result);
if (!isRegenerate)
{
final PropertyValue pv =
avmService.getNodeProperty(-1, formInstanceData.getPath(), WCMAppModel.PROP_RENDITIONS);
final Collection<Serializable> renditions = (pv == null
? new HashSet<Serializable>()
: pv.getCollection(DataTypeDefinition.TEXT));
renditions.add(AVMUtil.getStoreRelativePath(renditionAvmPath));
avmService.setNodeProperty(formInstanceData.getPath(),
WCMAppModel.PROP_RENDITIONS,
new PropertyValue(DataTypeDefinition.TEXT,
(Serializable)renditions));
}
return result;
}
public void render(final FormInstanceData formInstanceData,
final Rendition rendition)
throws IOException,
SAXException,
RenderingEngine.RenderingException
{
RenderingEngine re = this.getRenderingEngine();
if (re == null)
{
return;
}
final OutputStream out = rendition.getOutputStream();
try
{
re.render(this.buildModel(formInstanceData, rendition),
this,
out);
}
finally
{
out.close();
}
final Map<QName, PropertyValue> props = new HashMap<QName, PropertyValue>(5, 1.0f);
props.put(WCMAppModel.PROP_PARENT_FORM_NAME,
new PropertyValue(DataTypeDefinition.TEXT,
formInstanceData.getForm().getName()));
props.put(ContentModel.PROP_TITLE,
new PropertyValue(DataTypeDefinition.TEXT,
AVMNodeConverter.SplitBase(rendition.getPath())[1]));
final ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance());
props.put(ContentModel.PROP_DESCRIPTION,
new PropertyValue(DataTypeDefinition.TEXT,
MessageFormat.format(bundle.getString("default_rendition_description"),
this.getTitle(),
AVMUtil.getSandboxRelativePath(rendition.getPath()))));
props.put(WCMAppModel.PROP_PARENT_RENDERING_ENGINE_TEMPLATE,
new PropertyValue(DataTypeDefinition.NODE_REF,
this.nodeRef));
props.put(WCMAppModel.PROP_PARENT_RENDITION_PROPERTIES,
new PropertyValue(DataTypeDefinition.NODE_REF,
this.renditionPropertiesNodeRef));
// extract a store relative path for the primary form instance data
props.put(WCMAppModel.PROP_PRIMARY_FORM_INSTANCE_DATA,
new PropertyValue(DataTypeDefinition.TEXT,
AVMUtil.getStoreRelativePath(formInstanceData.getPath())));
final AVMService avmService = this.getServiceRegistry().getAVMLockingAwareService();
avmService.setNodeProperties(rendition.getPath(), props);
}
/**
* Builds the model to pass to the rendering engine.
*/
protected Map<QName, Object> buildModel(final FormInstanceData formInstanceData,
final Rendition rendition)
throws IOException,
SAXException
{
final String formInstanceDataAvmPath = formInstanceData.getPath();
final String renditionAvmPath = rendition.getPath();
final String parentPath = AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[0];
final String sandboxUrl = AVMUtil.getPreviewURI(AVMUtil.getStoreName(formInstanceDataAvmPath));
final String webappUrl = AVMUtil.buildWebappUrl(formInstanceDataAvmPath);
final HashMap<QName, Object> model = new HashMap<QName, Object>();
// add simple scalar parameters
model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX,
"date",
namespacePrefixResolver),
new Date());
model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX,
"avm_sandbox_url",
namespacePrefixResolver),
sandboxUrl);
model.put(RenderingEngineTemplateImpl.PROP_RESOURCE_RESOLVER,
new RenderingEngine.TemplateResourceResolver()
{
public InputStream resolve(final String name)
{
final NodeService nodeService =
RenderingEngineTemplateImpl.this.getServiceRegistry().getNodeService();
final NodeRef parentNodeRef =
nodeService.getPrimaryParent(RenderingEngineTemplateImpl.this.getNodeRef()).getParentRef();
if (logger.isDebugEnabled())
{
logger.debug("request to resolve resource " + name +
" webapp url is " + webappUrl +
" and data dictionary workspace is " + parentNodeRef);
}
final NodeRef result = nodeService.getChildByName(parentNodeRef, ContentModel.ASSOC_CONTAINS, name);
if (result != null)
{
final ContentService contentService =
RenderingEngineTemplateImpl.this.getServiceRegistry().getContentService();
try
{
if (logger.isDebugEnabled())
{
logger.debug("found " + name + " in data dictonary: " + result);
}
return contentService.getReader(result, ContentModel.PROP_CONTENT).getContentInputStream();
}
catch (Exception e)
{
logger.warn(e);
}
}
if (name.startsWith(WEBSCRIPT_PREFIX))
{
try
{
final FacesContext facesContext = FacesContext.getCurrentInstance();
final ExternalContext externalContext = facesContext.getExternalContext();
final HttpServletRequest request = (HttpServletRequest)externalContext.getRequest();
String decodedName = URLDecoder.decode(name.substring(WEBSCRIPT_PREFIX.length()));
String rewrittenName = decodedName;
if (decodedName.contains("${storeid}"))
{
rewrittenName = rewrittenName.replace("${storeid}", AVMUtil.getStoreName(formInstanceDataAvmPath));
}
else
{
if (decodedName.contains("{storeid}"))
{
rewrittenName = rewrittenName.replace("{storeid}", AVMUtil.getStoreName(formInstanceDataAvmPath));
}
}
if (decodedName.contains("${ticket}"))
{
AuthenticationService authenticationService = Repository.getServiceRegistry(facesContext).getAuthenticationService();
final String ticket = authenticationService.getCurrentTicket();
rewrittenName = rewrittenName.replace("${ticket}", ticket);
}
else
{
if (decodedName.contains("{ticket}"))
{
AuthenticationService authenticationService = Repository.getServiceRegistry(facesContext).getAuthenticationService();
final String ticket = authenticationService.getCurrentTicket();
rewrittenName = rewrittenName.replace("{ticket}", ticket);
}
}
final String webscriptURI = (request.getScheme() + "://" +
request.getServerName() + ':' +
request.getServerPort() +
request.getContextPath() + "/wcservice/" +
rewrittenName);
if (logger.isDebugEnabled())
{
logger.debug("loading webscript: " + webscriptURI);
}
final URI uri = new URI(webscriptURI);
return uri.toURL().openStream();
}
catch (Exception e)
{
logger.warn(e);
}
}
try
{
final String[] path = (name.startsWith("/") ? name.substring(1) : name).split("/");
for (int i = 0; i < path.length; i++)
{
path[i] = URLEncoder.encode(path[i]);
}
final URI uri = new URI(webappUrl + '/' + StringUtils.join(path, '/'));
if (logger.isDebugEnabled())
{
logger.debug("loading " + uri);
}
return uri.toURL().openStream();
}
catch (Exception e)
{
logger.warn(e);
return null;
}
}
});
model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX,
"form_instance_data_file_name",
namespacePrefixResolver),
AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[1]);
model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX,
"rendition_file_name",
namespacePrefixResolver),
AVMNodeConverter.SplitBase(renditionAvmPath)[1]);
model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX,
"parent_path",
namespacePrefixResolver),
parentPath);
final FacesContext fc = FacesContext.getCurrentInstance();
model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX,
"request_context_path",
namespacePrefixResolver),
fc.getExternalContext().getRequestContextPath());
// add methods
final FormDataFunctions fdf = this.getFormDataFunctions();
model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX,
"encodeQuotes",
namespacePrefixResolver),
new RenderingEngine.TemplateProcessorMethod()
{
public Object exec(final Object[] arguments)
throws IOException,
SAXException
{
if (arguments.length != 1)
{
throw new IllegalArgumentException("expected 1 argument to encodeQuotes. got " +
arguments.length);
}
if (! (arguments[0] instanceof String))
{
throw new ClassCastException("expected arguments[0] to be a " + String.class.getName() +
". got a " + arguments[0].getClass().getName() + ".");
}
String text = (String)arguments[0];
if (logger.isDebugEnabled())
{
logger.debug("tpm_encodeQuotes('" + text + "'), parentPath = " + parentPath);
}
final String result = fdf.encodeQuotes(text);
return result;
}
});
model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX,
"parseXMLDocument",
namespacePrefixResolver),
new RenderingEngine.TemplateProcessorMethod()
{
public Object exec(final Object[] arguments)
throws IOException,
SAXException
{
if (arguments.length != 1)
{
throw new IllegalArgumentException("expected 1 argument to parseXMLDocument. got " +
arguments.length);
}
if (! (arguments[0] instanceof String))
{
throw new ClassCastException("expected arguments[0] to be a " + String.class.getName() +
". got a " + arguments[0].getClass().getName() + ".");
}
String path = (String)arguments[0];
path = AVMUtil.buildPath(parentPath,
path,
AVMUtil.PathRelation.WEBAPP_RELATIVE);
if (logger.isDebugEnabled())
{
logger.debug("tpm_parseXMLDocument('" + path + "'), parentPath = " + parentPath);
}
final Document d = fdf.parseXMLDocument(path);
return d != null ? d.getDocumentElement() : null;
}
});
model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX,
"parseXMLDocuments",
namespacePrefixResolver),
new RenderingEngine.TemplateProcessorMethod()
{
public Object exec(final Object[] arguments)
throws IOException,
SAXException
{
if (arguments.length > 2)
{
throw new IllegalArgumentException("expected exactly one or two arguments to " +
"parseXMLDocuments. got " + arguments.length);
}
if (! (arguments[0] instanceof String))
{
throw new ClassCastException("expected arguments[0] to be a " + String.class.getName() +
". got a " + arguments[0].getClass().getName() + ".");
}
if (arguments.length == 2 && ! (arguments[1] instanceof String))
{
throw new ClassCastException("expected arguments[1] to be a " + String.class.getName() +
". got a " + arguments[1].getClass().getName() + ".");
}
String path = arguments.length == 2 ? (String)arguments[1] : "";
path = AVMUtil.buildPath(parentPath,
path,
AVMUtil.PathRelation.WEBAPP_RELATIVE);
final String formName = (String)arguments[0];
if (logger.isDebugEnabled())
{
logger.debug("tpm_parseXMLDocuments('" + formName + "','" + path +
"'), parentPath = " + parentPath);
}
final Map<String, Document> resultMap = fdf.parseXMLDocuments(formName, path);
if (logger.isDebugEnabled())
{
logger.debug("received " + resultMap.size() +
" documents in " + path +
" with form name " + formName);
}
// create a root document for rooting all the results. we do this
// so that each document root element has a common parent node
// and so that xpath axes work properly
final Document rootNodeDocument = XMLUtil.newDocument();
final Element rootNodeDocumentEl =
rootNodeDocument.createElementNS(NamespaceService.ALFRESCO_URI,
NamespaceService.ALFRESCO_PREFIX + ":file_list");
rootNodeDocumentEl.setAttribute("xmlns:" + NamespaceService.ALFRESCO_PREFIX,
NamespaceService.ALFRESCO_URI);
rootNodeDocument.appendChild(rootNodeDocumentEl);
final List<Node> result = new ArrayList<Node>(resultMap.size());
for (Map.Entry<String, Document> e : resultMap.entrySet())
{
final Element documentEl = e.getValue().getDocumentElement();
documentEl.setAttribute("xmlns:" + NamespaceService.ALFRESCO_PREFIX,
NamespaceService.ALFRESCO_URI);
documentEl.setAttributeNS(NamespaceService.ALFRESCO_URI,
NamespaceService.ALFRESCO_PREFIX + ":file_name",
e.getKey());
final Node n = rootNodeDocument.importNode(documentEl, true);
rootNodeDocumentEl.appendChild(n);
result.add(n);
}
return result.toArray(new Node[result.size()]);
}
});
model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX,
"_getAVMPath",
namespacePrefixResolver),
new RenderingEngine.TemplateProcessorMethod()
{
public Object exec(final Object[] arguments)
{
if (arguments.length != 1)
{
throw new IllegalArgumentException("expected one argument to _getAVMPath. got " +
arguments.length);
}
if (! (arguments[0] instanceof String))
{
throw new ClassCastException("expected arguments[0] to be a " + String.class.getName() +
". got a " + arguments[0].getClass().getName() + ".");
}
final String path = (String)arguments[0];
if (logger.isDebugEnabled())
{
logger.debug("tpm_getAVMPAth('" + path + "'), parentPath = " + parentPath);
}
return AVMUtil.buildPath(parentPath,
path,
AVMUtil.PathRelation.WEBAPP_RELATIVE);
}
});
// add the xml document
model.put(RenderingEngine.ROOT_NAMESPACE, formInstanceData.getDocument());
return model;
}
protected static FormDataFunctions getFormDataFunctions()
{
final FacesContext fc = FacesContext.getCurrentInstance();
final WebApplicationContext wac =
FacesContextUtils.getRequiredWebApplicationContext(fc);
return new FormDataFunctions((AVMRemote)wac.getBean("avmRemote"));
}
private ServiceRegistry getServiceRegistry()
{
final FacesContext fc = FacesContext.getCurrentInstance();
return Repository.getServiceRegistry(fc);
}
public int hashCode()
{
return this.getName().hashCode();
}
public String toString()
{
return this.getClass().getName() + "{name : " + this.getName() + "}";
}
public boolean isExists()
{
final NodeService nodeService = this.getServiceRegistry().getNodeService();
return nodeService.exists(this.nodeRef);
}
}