mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
7740: Fix to display better error messages for errors when restricting WCM File Picker to configured search 7993: Added missing explicit AVM index. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8449 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
1071 lines
39 KiB
Java
1071 lines
39 KiB
Java
/*
|
|
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
* As a special exception to the terms and conditions of version 2.0 of
|
|
* the GPL, you may redistribute this Program in connection with Free/Libre
|
|
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
|
* FLOSS exception. You should have recieved a copy of the text describing
|
|
* the FLOSS exception, and it is also available here:
|
|
* http://www.alfresco.com/legal/licensing"
|
|
*/
|
|
package org.alfresco.web.bean.wcm;
|
|
|
|
import java.io.InputStream;
|
|
import java.io.Serializable;
|
|
import java.text.MessageFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.regex.Pattern;
|
|
|
|
import javax.faces.context.ExternalContext;
|
|
import javax.faces.context.FacesContext;
|
|
import javax.faces.context.ResponseWriter;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
|
import org.alfresco.error.AlfrescoRuntimeException;
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.model.WCMModel;
|
|
import org.alfresco.repo.avm.AVMNodeConverter;
|
|
import org.alfresco.repo.content.MimetypeMap;
|
|
import org.alfresco.repo.domain.PropertyValue;
|
|
import org.alfresco.repo.search.SearcherException;
|
|
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
|
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
|
|
import org.alfresco.service.cmr.avm.AVMService;
|
|
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
|
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
|
import org.alfresco.service.cmr.repository.ContentReader;
|
|
import org.alfresco.service.cmr.repository.ContentService;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.repository.NodeService;
|
|
import org.alfresco.service.cmr.repository.StoreRef;
|
|
import org.alfresco.service.cmr.search.ResultSet;
|
|
import org.alfresco.service.cmr.search.ResultSetRow;
|
|
import org.alfresco.service.cmr.search.SearchService;
|
|
import org.alfresco.service.namespace.NamespaceService;
|
|
import org.alfresco.service.namespace.QName;
|
|
import org.alfresco.service.namespace.RegexQNamePattern;
|
|
import org.alfresco.util.Pair;
|
|
import org.alfresco.web.app.Application;
|
|
import org.alfresco.web.app.servlet.ajax.InvokeCommand;
|
|
import org.alfresco.web.bean.FileUploadBean;
|
|
import org.alfresco.web.bean.repository.Node;
|
|
import org.alfresco.web.bean.repository.Repository;
|
|
import org.alfresco.web.forms.XMLUtil;
|
|
import org.alfresco.web.ui.common.Utils;
|
|
import org.apache.commons.fileupload.FileItem;
|
|
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
|
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
|
import org.apache.commons.io.FilenameUtils;
|
|
import org.apache.commons.lang.StringUtils;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
import org.dom4j.Document;
|
|
import org.dom4j.DocumentException;
|
|
import org.dom4j.DocumentHelper;
|
|
import org.dom4j.Element;
|
|
import org.dom4j.XPath;
|
|
import org.dom4j.io.SAXReader;
|
|
import org.springframework.util.FileCopyUtils;
|
|
|
|
/**
|
|
* Bean for interacting with the file picker widget using ajax requests.
|
|
*/
|
|
public class FilePickerBean implements Serializable
|
|
{
|
|
private static final Log LOGGER = LogFactory.getLog(FilePickerBean.class);
|
|
|
|
private static final String CONFIGURED_SEARCH_QUERY_XPATH = "/search/query";
|
|
private static final String CDATA_START_DELIM = "![CDATA[";
|
|
private static final String CDATA_END_DELIM = "]]";
|
|
|
|
// parameter names
|
|
private static final String PARAM_FOLDER_RESTRICTION = "folderRestriction";
|
|
private static final String PARAM_CONFIGURED_SEARCH_NAME = "configSearchName";
|
|
private static final String PARAM_SELECTABLE_TYPES = "selectableTypes";
|
|
private static final String PARAM_FILTER_MIME_TYPES = "filterMimetypes";
|
|
private static final String PARAM_CURRENT_PATH = "currentPath";
|
|
|
|
private final Set<NodeRef> uploads = new HashSet<NodeRef>();
|
|
|
|
// property instance variables
|
|
private AVMBrowseBean avmBrowseBean;
|
|
transient private AVMService avmService;
|
|
transient private NamespaceService namespaceService;
|
|
transient private SearchService searchService;
|
|
transient private NodeService nodeService;
|
|
transient private DictionaryService dictionaryService;
|
|
transient private ContentService contentService;
|
|
|
|
// cached reference to the public saved searches folder
|
|
private NodeRef publicSearchesRef = null;
|
|
|
|
// initial current folder - the current folder path which the
|
|
// the file picker opens at when first selected in the form
|
|
private String initialCurrentPath = null;
|
|
|
|
public FilePickerBean()
|
|
{
|
|
}
|
|
|
|
public void clearUploadedFiles()
|
|
{
|
|
this.uploads.clear();
|
|
}
|
|
|
|
public NodeRef[] getUploadedFiles()
|
|
{
|
|
return (NodeRef[]) this.uploads.toArray(new NodeRef[this.uploads.size()]);
|
|
}
|
|
|
|
/**
|
|
* Set avmBrowseBean property for this bean
|
|
*
|
|
* @param avmBrowseBean
|
|
* the AVMBrowseBean object to pass into this property
|
|
*/
|
|
public void setAvmBrowseBean(final AVMBrowseBean avmBrowseBean)
|
|
{
|
|
this.avmBrowseBean = avmBrowseBean;
|
|
}
|
|
|
|
/**
|
|
* Get avmBrowseBean property for this bean
|
|
*
|
|
* @return avmBrowseBean property value for this bean
|
|
*/
|
|
public AVMBrowseBean getAvmBrowseBean()
|
|
{
|
|
return this.avmBrowseBean;
|
|
}
|
|
|
|
/**
|
|
* Set avmService property for this bean
|
|
*
|
|
* @param avmService
|
|
* the avmService object to pass into this property
|
|
*/
|
|
public void setAvmService(final AVMService avmService)
|
|
{
|
|
this.avmService = avmService;
|
|
}
|
|
|
|
/**
|
|
* Get avmService property for this bean
|
|
*
|
|
* @return avmService property value for this bean
|
|
*/
|
|
public AVMService getAvmService()
|
|
{
|
|
if (this.avmService == null)
|
|
{
|
|
this.avmService = Repository.getServiceRegistry(
|
|
FacesContext.getCurrentInstance()).getAVMService();
|
|
}
|
|
return this.avmService;
|
|
}
|
|
|
|
/**
|
|
* Set nodeService property value for this bean
|
|
*
|
|
* @param nodeService
|
|
* the NodeService object to pass into this property
|
|
*/
|
|
public void setNodeService(final NodeService nodeService)
|
|
{
|
|
this.nodeService = nodeService;
|
|
}
|
|
|
|
/**
|
|
* Get nodeService property for this bean
|
|
*
|
|
* @return nodeService property value for this bean
|
|
*/
|
|
public NodeService getNodeService()
|
|
{
|
|
if (this.nodeService == null)
|
|
{
|
|
this.nodeService = Repository.getServiceRegistry(
|
|
FacesContext.getCurrentInstance()).getNodeService();
|
|
}
|
|
return this.nodeService;
|
|
}
|
|
|
|
/**
|
|
* Set searchService property for this bean
|
|
*
|
|
* @param searchService
|
|
* the SearchService object to pass into this property
|
|
*/
|
|
public void setSearchService(final SearchService searchService)
|
|
{
|
|
this.searchService = searchService;
|
|
}
|
|
|
|
/**
|
|
* Get SearchService property for this bean
|
|
*
|
|
* @return searchService property value for this bean
|
|
*/
|
|
public SearchService getSearchService()
|
|
{
|
|
if (this.searchService == null)
|
|
{
|
|
this.searchService = Repository.getServiceRegistry(
|
|
FacesContext.getCurrentInstance()).getSearchService();
|
|
}
|
|
return this.searchService;
|
|
}
|
|
|
|
/**
|
|
* Set dictionaryService property value for this bean
|
|
*
|
|
* @param dictionaryService
|
|
* the DictionaryService object to pass into this property
|
|
*/
|
|
public void setDictionaryService(final DictionaryService dictionaryService)
|
|
{
|
|
this.dictionaryService = dictionaryService;
|
|
}
|
|
|
|
/**
|
|
* Get dictionaryService property for this bean
|
|
*
|
|
* @return dictionaryService property value for this bean
|
|
*/
|
|
public DictionaryService getDictionaryService()
|
|
{
|
|
if (this.dictionaryService == null)
|
|
{
|
|
this.dictionaryService = Repository.getServiceRegistry(
|
|
FacesContext.getCurrentInstance()).getDictionaryService();
|
|
}
|
|
return this.dictionaryService;
|
|
}
|
|
|
|
/**
|
|
* Set namespaceService property for this bean
|
|
*
|
|
* @param namespaceService
|
|
* the NamespaceService object to pass into this property
|
|
*/
|
|
public void setNamespaceService(final NamespaceService namespaceService)
|
|
{
|
|
this.namespaceService = namespaceService;
|
|
}
|
|
|
|
/**
|
|
* Get the namespaceService property value for this bean
|
|
*
|
|
* @return namespaceService property value for this bean
|
|
*/
|
|
public NamespaceService getNamespaceService()
|
|
{
|
|
if (this.namespaceService == null)
|
|
{
|
|
this.namespaceService = Repository.getServiceRegistry(
|
|
FacesContext.getCurrentInstance()).getNamespaceService();
|
|
}
|
|
return this.namespaceService;
|
|
}
|
|
|
|
/**
|
|
* Set contentService property
|
|
*
|
|
* @param contentService
|
|
* the ContentService object to pass into this property
|
|
*/
|
|
public void setContentService(final ContentService contentService)
|
|
{
|
|
this.contentService = contentService;
|
|
}
|
|
|
|
/**
|
|
* Get contentService property value for this bean
|
|
*
|
|
* @return contentService property value for this bean
|
|
*/
|
|
public ContentService getContentService()
|
|
{
|
|
if (this.contentService == null)
|
|
{
|
|
this.contentService = Repository.getServiceRegistry(
|
|
FacesContext.getCurrentInstance()).getContentService();
|
|
}
|
|
return this.contentService;
|
|
}
|
|
|
|
/**
|
|
* Provides data for a file picker widget.
|
|
*/
|
|
@InvokeCommand.ResponseMimetype(value = MimetypeMap.MIMETYPE_XML)
|
|
public void getFilePickerData() throws Exception
|
|
{
|
|
final FacesContext facesContext = FacesContext.getCurrentInstance();
|
|
final ExternalContext externalContext = facesContext.getExternalContext();
|
|
|
|
// get configured search name parameter value
|
|
String configSearchName = null;
|
|
String[] configSearchNameParam = (String[]) externalContext
|
|
.getRequestParameterValuesMap().get(PARAM_CONFIGURED_SEARCH_NAME);
|
|
if ((configSearchNameParam != null)
|
|
&& (configSearchNameParam.length != 0))
|
|
{
|
|
configSearchName = configSearchNameParam[0];
|
|
}
|
|
|
|
// get selectableTypes parameter value
|
|
final QName[] selectableTypes = this
|
|
.getSelectableTypes((String[]) externalContext
|
|
.getRequestParameterValuesMap().get(PARAM_SELECTABLE_TYPES));
|
|
|
|
// / get filterMimetypes parameter value
|
|
final Pattern[] filterMimetypes = this
|
|
.getFilterMimetypes((String[]) externalContext
|
|
.getRequestParameterValuesMap().get(PARAM_FILTER_MIME_TYPES));
|
|
|
|
// get 'folderRestriction' parameter value
|
|
// expecting a relative AVM folder path to be held in this parameter
|
|
// (relative to web project webapp root)
|
|
String folderPathRestriction = null;
|
|
String[] folderPathRestrictionParam = (String[]) externalContext
|
|
.getRequestParameterValuesMap().get(PARAM_FOLDER_RESTRICTION);
|
|
if ((folderPathRestrictionParam != null)
|
|
&& (folderPathRestrictionParam.length != 0))
|
|
{
|
|
folderPathRestriction = folderPathRestrictionParam[0];
|
|
|
|
// remove leading '/' or '\' (if present) from path restriction
|
|
if ((folderPathRestriction.charAt(0) == '/')
|
|
|| (folderPathRestriction.charAt(0) == '\\'))
|
|
{
|
|
folderPathRestriction = folderPathRestriction.substring(1);
|
|
}
|
|
}
|
|
|
|
// ###
|
|
// the following section sets file picker current path (the folder that
|
|
// file picker
|
|
// is opened at when selected/changed in the form)
|
|
|
|
String currentPath = null;
|
|
|
|
// get current path request parameter
|
|
String currentPathReqParam = (String) externalContext
|
|
.getRequestParameterMap().get(PARAM_CURRENT_PATH);
|
|
|
|
// if current path request parameter null then set current path to the
|
|
// current AVM path
|
|
if ((currentPathReqParam == null))
|
|
{
|
|
currentPath = this.getCurrentAVMPath();
|
|
}
|
|
// else set current path to current path request parameter converted to
|
|
// AVM preview
|
|
// store path
|
|
else
|
|
{
|
|
final String previewStorePath = AVMUtil
|
|
.getCorrespondingPathInPreviewStore(this.getCurrentAVMPath());
|
|
currentPath = AVMUtil.buildPath(previewStorePath, currentPathReqParam,
|
|
AVMUtil.PathRelation.WEBAPP_RELATIVE);
|
|
}
|
|
|
|
// if initial current path not set then set it to the current path
|
|
if (initialCurrentPath == null)
|
|
{
|
|
initialCurrentPath = currentPath;
|
|
|
|
// insert '/' at end of initial current path if there isn't one
|
|
if (initialCurrentPath.charAt(initialCurrentPath.length() - 1) != '/')
|
|
{
|
|
initialCurrentPath = initialCurrentPath + "/";
|
|
}
|
|
}
|
|
|
|
// if folder path restriction (relative path) is set,
|
|
// then calculate the absolute restriction path (in context of file
|
|
// picker's
|
|
// initial current path - the path at which it was opened the first time)
|
|
// and set file picker current path to that
|
|
if ((folderPathRestriction != null)
|
|
&& (folderPathRestriction.length() != 0))
|
|
{
|
|
currentPath = initialCurrentPath + folderPathRestriction;
|
|
}
|
|
|
|
if (LOGGER.isDebugEnabled())
|
|
{
|
|
LOGGER.debug(this + ".getFilePickerData(path = " + currentPath
|
|
+ ", selectableTypes = ["
|
|
+ StringUtils.join(selectableTypes, ",")
|
|
+ "], filterMimetypes = ["
|
|
+ StringUtils.join(filterMimetypes, ",") + "])");
|
|
}
|
|
|
|
// create file picker data XML document to return
|
|
// and append file picker data element to it
|
|
final org.w3c.dom.Document filePickerDataDoc = XMLUtil.newDocument();
|
|
final org.w3c.dom.Element filePickerDataElement = filePickerDataDoc
|
|
.createElement("file-picker-data");
|
|
filePickerDataDoc.appendChild(filePickerDataElement);
|
|
|
|
// make sure that there is a node associated with current path
|
|
// if not, set an applicable error message as an attribute on
|
|
// the file picker data element
|
|
final AVMNodeDescriptor currentNode = this.getAvmService().lookup(-1,
|
|
currentPath);
|
|
|
|
// if the current node is null (path held in current path variable is
|
|
// invalid), then add an error attribute to the file picker data
|
|
if (currentNode == null)
|
|
{
|
|
currentPath = AVMUtil.getWebappRelativePath(currentPath);
|
|
|
|
filePickerDataElement.setAttribute("error", MessageFormat.format(
|
|
Application.getMessage(facesContext, "error_not_found"),
|
|
"'" + currentPath.substring(currentPath.lastIndexOf("/") + 1, currentPath.length()) + "'",
|
|
(currentPath.lastIndexOf("/") == 0 ? "/" : currentPath.substring(
|
|
0, currentPath.lastIndexOf("/")))));
|
|
|
|
// If folder restriction has been set, since the derived
|
|
// current path is invalid just set it to null
|
|
if ((folderPathRestriction != null)
|
|
&& (folderPathRestriction.length() != 0))
|
|
{
|
|
currentPath = null;
|
|
} else
|
|
// otherwise folder restriction has not been set, so it should be safe
|
|
// to fall back to setting the current path to the current AVM path
|
|
// (as was the behaviour before the folder restriction feature
|
|
// was added)
|
|
{
|
|
currentPath = this.getCurrentAVMPath();
|
|
}
|
|
}
|
|
// else current node is not null (path held in current path variable is
|
|
// valid)
|
|
else
|
|
{
|
|
// if node for current path points to a file instead of a directory,
|
|
// then make sure that the current path points to
|
|
// just the directory part of the path
|
|
if (!currentNode.isDirectory())
|
|
{
|
|
currentPath = AVMNodeConverter.SplitBase(currentPath)[0];
|
|
}
|
|
}
|
|
|
|
// create current-node element representing node for current path
|
|
// and append it to the file picker data element
|
|
org.w3c.dom.Element currentNodeElement = filePickerDataDoc
|
|
.createElement("current-node");
|
|
if (currentPath == null)
|
|
{
|
|
currentNodeElement.setAttribute("avmPath", "");
|
|
currentNodeElement.setAttribute("webappRelativePath", "");
|
|
} else
|
|
{
|
|
currentNodeElement.setAttribute("avmPath", currentPath);
|
|
currentNodeElement.setAttribute("webappRelativePath", AVMUtil
|
|
.getWebappRelativePath(currentPath));
|
|
}
|
|
currentNodeElement.setAttribute("type", "directory");
|
|
currentNodeElement.setAttribute("image", "/images/icons/space_small.gif");
|
|
|
|
filePickerDataElement.appendChild(currentNodeElement);
|
|
|
|
// if configured search name supplied (i.e. neither null nor empty),
|
|
// then get configured search node matching given name
|
|
// and add the nodes from the search result to the
|
|
// file-picker-data element
|
|
if ((configSearchName != null) && (configSearchName.length() != 0))
|
|
{
|
|
// get node reference for named configured search
|
|
NodeRef configuredSearchNodeRef = getConfiguredSearches(configSearchName);
|
|
|
|
// if configured search node ref is null, then there is no
|
|
// configured search matching the name in the 'config search name'
|
|
// parameter, so add error message as attribute to file-picker-data
|
|
// element
|
|
if (configuredSearchNodeRef == null)
|
|
{
|
|
filePickerDataElement.setAttribute("error", MessageFormat.format(
|
|
Application.getMessage(facesContext, "error_search_not_exist"),
|
|
configSearchName));
|
|
}
|
|
else
|
|
// else node ref for named configured search is not null, then
|
|
// add content nodes from search results as child elements of
|
|
// the file picker data element.
|
|
{
|
|
try
|
|
{
|
|
addSearchResultNodes(filePickerDataDoc, filePickerDataElement,
|
|
configuredSearchNodeRef, selectableTypes, facesContext);
|
|
}
|
|
// if searcher exception thrown whilst getting search results,
|
|
// then add error message as attribute to file-picker-data element
|
|
catch (SearcherException e)
|
|
{
|
|
filePickerDataElement.setAttribute("error", MessageFormat.format(
|
|
Application.getMessage(facesContext, "error_retrieving_search_results"),
|
|
configSearchName, e.getMessage()));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// add elements for child nodes of current path to file picker
|
|
// data element if current path is not null
|
|
if (currentPath != null)
|
|
{
|
|
addPathChildNodesToElement(filePickerDataDoc,
|
|
filePickerDataElement, currentPath, selectableTypes,
|
|
filterMimetypes, facesContext);
|
|
}
|
|
}
|
|
|
|
final ResponseWriter out = facesContext.getResponseWriter();
|
|
XMLUtil.print(filePickerDataDoc, out);
|
|
}
|
|
|
|
@InvokeCommand.ResponseMimetype(value = MimetypeMap.MIMETYPE_HTML)
|
|
public void uploadFile() throws Exception
|
|
{
|
|
LOGGER.debug(this + ".uploadFile()");
|
|
final FacesContext facesContext = FacesContext.getCurrentInstance();
|
|
final ExternalContext externalContext = facesContext.getExternalContext();
|
|
final HttpServletRequest request = (HttpServletRequest) externalContext
|
|
.getRequest();
|
|
|
|
final ServletFileUpload upload = new ServletFileUpload(
|
|
new DiskFileItemFactory());
|
|
upload.setHeaderEncoding("UTF-8");
|
|
final List<FileItem> fileItems = upload.parseRequest(request);
|
|
final FileUploadBean bean = new FileUploadBean();
|
|
String uploadId = null;
|
|
String currentPath = null;
|
|
String filename = null;
|
|
String returnPage = null;
|
|
InputStream fileInputStream = null;
|
|
for (FileItem item : fileItems)
|
|
{
|
|
if (LOGGER.isDebugEnabled())
|
|
{
|
|
LOGGER.debug("item = " + item);
|
|
}
|
|
if (item.isFormField() && item.getFieldName().equals("upload-id"))
|
|
{
|
|
uploadId = item.getString();
|
|
if (LOGGER.isDebugEnabled())
|
|
{
|
|
LOGGER.debug("uploadId is " + uploadId);
|
|
}
|
|
}
|
|
if (item.isFormField() && item.getFieldName().equals("return-page"))
|
|
{
|
|
returnPage = item.getString();
|
|
if (LOGGER.isDebugEnabled())
|
|
{
|
|
LOGGER.debug("returnPage is " + returnPage);
|
|
}
|
|
} else if (item.isFormField()
|
|
&& item.getFieldName().equals("currentPath"))
|
|
{
|
|
final String previewStorePath = AVMUtil
|
|
.getCorrespondingPathInPreviewStore(this.getCurrentAVMPath());
|
|
currentPath = AVMUtil.buildPath(previewStorePath, item.getString(),
|
|
AVMUtil.PathRelation.WEBAPP_RELATIVE);
|
|
if (LOGGER.isDebugEnabled())
|
|
{
|
|
LOGGER.debug("currentPath is " + currentPath);
|
|
}
|
|
} else
|
|
{
|
|
filename = FilenameUtils.getName(item.getName());
|
|
fileInputStream = item.getInputStream();
|
|
|
|
if (LOGGER.isDebugEnabled())
|
|
{
|
|
LOGGER.debug("uploading file " + filename);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (LOGGER.isDebugEnabled())
|
|
{
|
|
LOGGER.debug("saving file " + filename + " to " + currentPath);
|
|
}
|
|
|
|
try
|
|
{
|
|
FileCopyUtils.copy(fileInputStream, this.getAvmService().createFile(
|
|
currentPath, filename));
|
|
final Map<QName, PropertyValue> props = new HashMap<QName, PropertyValue>(
|
|
1, 1.0f);
|
|
props.put(ContentModel.PROP_TITLE, new PropertyValue(
|
|
DataTypeDefinition.TEXT, filename));
|
|
// props.put(ContentModel.PROP_DESCRIPTION,
|
|
// new PropertyValue(DataTypeDefinition.TEXT,
|
|
// "Uploaded for form " + this.xformsSession.getForm().getName()));
|
|
this.getAvmService().setNodeProperties(currentPath + "/" + filename,
|
|
props);
|
|
this.getAvmService().addAspect(currentPath + "/" + filename,
|
|
ContentModel.ASPECT_TITLED);
|
|
|
|
this.uploads.add(AVMNodeConverter.ToNodeRef(-1, currentPath + "/"
|
|
+ filename));
|
|
returnPage = returnPage.replace("${_FILE_TYPE_IMAGE}", Utils
|
|
.getFileTypeImage(facesContext, filename, true));
|
|
} catch (Exception e)
|
|
{
|
|
LOGGER.debug(e.getMessage(), e);
|
|
returnPage = returnPage.replace("${_UPLOAD_ERROR}", e.getMessage());
|
|
}
|
|
|
|
LOGGER.debug("upload complete. sending response: " + returnPage);
|
|
final org.w3c.dom.Document result = XMLUtil.newDocument();
|
|
final org.w3c.dom.Element htmlEl = result.createElement("html");
|
|
result.appendChild(htmlEl);
|
|
final org.w3c.dom.Element bodyEl = result.createElement("body");
|
|
htmlEl.appendChild(bodyEl);
|
|
|
|
final org.w3c.dom.Element scriptEl = result.createElement("script");
|
|
bodyEl.appendChild(scriptEl);
|
|
scriptEl.setAttribute("type", "text/javascript");
|
|
final org.w3c.dom.Node scriptText = result.createTextNode(returnPage);
|
|
scriptEl.appendChild(scriptText);
|
|
|
|
final ResponseWriter out = facesContext.getResponseWriter();
|
|
XMLUtil.print(result, out);
|
|
}
|
|
|
|
private String getCurrentAVMPath()
|
|
{
|
|
final AVMNode node = this.getAvmBrowseBean().getAvmActionNode();
|
|
if (node == null)
|
|
{
|
|
return this.getAvmBrowseBean().getCurrentPath();
|
|
}
|
|
|
|
final String result = node.getPath();
|
|
return node.isDirectory() ? result
|
|
: AVMNodeConverter.SplitBase(result)[0];
|
|
}
|
|
|
|
private QName[] getSelectableTypes(final String[] selectableTypes)
|
|
{
|
|
final QName[] result = (selectableTypes == null ? new QName[]
|
|
{ WCMModel.TYPE_AVM_CONTENT, WCMModel.TYPE_AVM_FOLDER }
|
|
: new QName[selectableTypes.length]);
|
|
|
|
if (selectableTypes != null)
|
|
{
|
|
for (int i = 0; i < selectableTypes.length; i++)
|
|
{
|
|
result[i] = QName.resolveToQName(this.getNamespaceService(),
|
|
selectableTypes[i]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private Pattern[] getFilterMimetypes(final String[] filterMimetypes)
|
|
{
|
|
final Pattern[] result = filterMimetypes == null ? new Pattern[0]
|
|
: new Pattern[filterMimetypes.length];
|
|
if (filterMimetypes != null)
|
|
{
|
|
for (int i = 0; i < filterMimetypes.length; i++)
|
|
{
|
|
result[i] = Pattern.compile(filterMimetypes[i].replaceAll("\\*",
|
|
"\\.*").replaceAll("\\/", "\\\\/"));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Add child nodes of supplied path to given parent element. Directory
|
|
* listing is done on given path. Elements representing the child nodes
|
|
* returned in the directory listing are added to the supplied parent
|
|
* element.
|
|
*
|
|
* @param doc
|
|
* XML document to which the parent node belongs
|
|
* @param parent
|
|
* parent element to add given nodes to as child elements
|
|
* @param path
|
|
* path from which to extract child nodes
|
|
* @param selectableTypes
|
|
* array of types which are the only ones that should be selectable
|
|
* in the file picker
|
|
* @param filterMimetypes
|
|
* array of MIME type patterns used to filter out child nodes
|
|
* extracted from the given path which don't match the given MIME
|
|
* type patterns
|
|
* @param facesContext
|
|
* faces context used to set image attribute on each child element
|
|
*/
|
|
private void addPathChildNodesToElement(org.w3c.dom.Document doc,
|
|
org.w3c.dom.Element parent, String path, QName[] selectableTypes,
|
|
Pattern[] filterMimetypes, FacesContext facesContext)
|
|
{
|
|
// append elements for the child AVM nodes of the current path
|
|
// to parent element
|
|
for (final Map.Entry<String, AVMNodeDescriptor> entry : this
|
|
.getAvmService().getDirectoryListing(-1, path).entrySet())
|
|
{
|
|
// if AVM node is a content node and the filter MIME types parameter
|
|
// has been set, then only add child element for AVM node if it matches
|
|
// one of the specified MIME types in the parameter
|
|
if (!entry.getValue().isDirectory() && filterMimetypes.length != 0)
|
|
{
|
|
final String contentMimetype = this.getAvmService()
|
|
.getContentDataForRead(entry.getValue()).getMimetype();
|
|
|
|
boolean matched = false;
|
|
for (final Pattern p : filterMimetypes)
|
|
{
|
|
matched = p.matcher(contentMimetype).matches();
|
|
if (LOGGER.isDebugEnabled())
|
|
{
|
|
LOGGER.debug(p + ".matches(" + contentMimetype + ") = "
|
|
+ matched);
|
|
}
|
|
if (matched)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if AVM node MIME type doesn't match any of the types in the
|
|
// filter MIME types parameter, then don't do any further processing
|
|
// on it and jump back to the start of the AVM node traversal loop
|
|
if (!matched)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// create child element representing AVM node and add to file picker
|
|
// data element
|
|
addAVMChildNodeToParentElement(doc, parent, entry.getValue(),
|
|
selectableTypes, facesContext);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add result content nodes from configured search as
|
|
* child node elements to the provided parent element
|
|
*
|
|
* @param doc
|
|
* XML document to which the supplied parent node belongs
|
|
* @param parent
|
|
* parent element to which to add search result content nodes
|
|
* as child elements
|
|
* @param configuredSearchNodeRef
|
|
* configured search node reference for which result content nodes
|
|
* are added as child elements to the provided parent element
|
|
* @param selectableTypes
|
|
* node types which must be marked as selectable in the file
|
|
* picker
|
|
* @param facesContext
|
|
* faces context used to set image attribute on each child element
|
|
*/
|
|
private void addSearchResultNodes(org.w3c.dom.Document doc,
|
|
org.w3c.dom.Element parent, NodeRef configuredSearchNodeRef,
|
|
QName[] selectableTypes, FacesContext facesContext)
|
|
{
|
|
// run configured search to get content nodes returned in search result
|
|
List<AVMNodeDescriptor> searchResultNodes = runConfiguredSearch(configuredSearchNodeRef);
|
|
|
|
// if there are no search results (i.e. null) throw exception
|
|
if (searchResultNodes == null)
|
|
{
|
|
throw new SearcherException("No results returned by search query.\n"
|
|
+ "Search node reference: " + configuredSearchNodeRef);
|
|
}
|
|
|
|
for (AVMNodeDescriptor node : searchResultNodes)
|
|
{
|
|
// create child element representing AVM node and add to file picker
|
|
// data element
|
|
addAVMChildNodeToParentElement(doc, parent, node, selectableTypes,
|
|
facesContext);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run a configured search represented by the given node reference, against
|
|
* the web project the XForm is currently within
|
|
*
|
|
* @param configuredQueryNodRef
|
|
* NodeRef of the configured query with which to run the search
|
|
*
|
|
* @return content nodes returned by the search
|
|
*/
|
|
private List<AVMNodeDescriptor> runConfiguredSearch(
|
|
NodeRef configSearchNodeRef)
|
|
{
|
|
// get the store id used to run the configured search query
|
|
WebProject webProject = this.getAvmBrowseBean().getWebProject();
|
|
String storeID = webProject.getStoreId();
|
|
|
|
// extract the content of configured search node to XML document
|
|
ContentReader contentReader = getContentService().getReader(
|
|
configSearchNodeRef, ContentModel.PROP_CONTENT);
|
|
InputStream queryInpStream = contentReader.getContentInputStream();
|
|
SAXReader reader = new SAXReader();
|
|
Document queryDoc = null;
|
|
try
|
|
{
|
|
queryDoc = reader.read(queryInpStream);
|
|
} catch (DocumentException de)
|
|
{
|
|
// ignore exception and return null
|
|
return null;
|
|
}
|
|
|
|
// extract search query from configured search XML document
|
|
String query = null;
|
|
XPath queryXPath = DocumentHelper
|
|
.createXPath(CONFIGURED_SEARCH_QUERY_XPATH);
|
|
List xpathResult = queryXPath.selectNodes(queryDoc);
|
|
if ((xpathResult != null) && (xpathResult.size() != 0))
|
|
{
|
|
// get the text from the query element
|
|
Element queryElement = (Element) xpathResult.get(0);
|
|
String queryElemText = queryElement.getText();
|
|
|
|
// now extract the actual search query string from the CDATA section
|
|
// within that text
|
|
|
|
int cdataStartDelimIndex = queryElemText.indexOf(CDATA_START_DELIM);
|
|
int cdataEndDelimIndex = queryElemText.indexOf(CDATA_END_DELIM);
|
|
|
|
// if the CDATA start delimiter is found in the query element text
|
|
// && there is text between the CDATA start and end delimiters then
|
|
// extract
|
|
// the query string from the CDATA section
|
|
if ((cdataStartDelimIndex > -1)
|
|
&& ((cdataStartDelimIndex + CDATA_START_DELIM.length()) < cdataEndDelimIndex))
|
|
{
|
|
query = queryElemText.substring(cdataStartDelimIndex
|
|
+ CDATA_START_DELIM.length(), cdataEndDelimIndex);
|
|
}
|
|
}
|
|
|
|
// perform the search against the repository
|
|
// if query was extracted from the configured search successfully
|
|
// (extracted query non-null)
|
|
List<AVMNodeDescriptor> resultNodeDescriptors = null;
|
|
if ((query != null) && (query.length() != 0))
|
|
{
|
|
ResultSet results = null;
|
|
try
|
|
{
|
|
results = this.getSearchService().query(
|
|
new StoreRef(StoreRef.PROTOCOL_AVM, storeID),
|
|
SearchService.LANGUAGE_LUCENE, query);
|
|
|
|
if (results.length() != 0)
|
|
{
|
|
resultNodeDescriptors = new ArrayList<AVMNodeDescriptor>();
|
|
for (int i = 0; i < results.length(); i++)
|
|
{
|
|
ResultSetRow row = results.getRow(i);
|
|
NodeRef resultNodeRef = row.getNodeRef();
|
|
Node resultNode = new Node(resultNodeRef);
|
|
|
|
// only add content type nodes to the search result
|
|
// as we don't want the user to navigate down into folders
|
|
// in the search results
|
|
if (getDictionaryService().isSubClass(resultNode.getType(),
|
|
ContentModel.TYPE_CONTENT))
|
|
{
|
|
Pair<Integer, String> pair = AVMNodeConverter
|
|
.ToAVMVersionPath(resultNodeRef);
|
|
Integer version = pair.getFirst();
|
|
String path = pair.getSecond();
|
|
resultNodeDescriptors.add(getAvmService().lookup(version,
|
|
path));
|
|
}
|
|
}
|
|
}
|
|
} catch (Throwable err)
|
|
{
|
|
throw new AlfrescoRuntimeException("Failed to execute search: "
|
|
+ query, err);
|
|
} finally
|
|
{
|
|
if (results != null)
|
|
{
|
|
results.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
return resultNodeDescriptors;
|
|
}
|
|
|
|
/**
|
|
* Get the cached reference to the public saved searches folder. This method
|
|
* will first get a reference to the public saved searches folder and assign
|
|
* it to the cached reference if is it is null.
|
|
*
|
|
* @return the cached reference to the public Saved Searches folder
|
|
*/
|
|
private NodeRef getPublicSearchesRef()
|
|
{
|
|
// if the cached reference is null, then get a reference to the
|
|
// public saved searches folder to assign to it
|
|
if (publicSearchesRef == null)
|
|
{
|
|
// Use the search service get a reference to the
|
|
// public saved searches folder.
|
|
FacesContext fc = FacesContext.getCurrentInstance();
|
|
String xpath = Application.getRootPath(fc) + "/"
|
|
+ Application.getGlossaryFolderName(fc) + "/"
|
|
+ Application.getSavedSearchesFolderName(fc);
|
|
|
|
List<NodeRef> results = null;
|
|
try
|
|
{
|
|
results = getSearchService().selectNodes(
|
|
getNodeService().getRootNode(Repository.getStoreRef()),
|
|
xpath, null, getNamespaceService(), false);
|
|
} catch (AccessDeniedException err)
|
|
{
|
|
// ignore and return null
|
|
}
|
|
|
|
if (results != null && results.size() != 0)
|
|
{
|
|
publicSearchesRef = results.get(0);
|
|
}
|
|
}
|
|
|
|
return publicSearchesRef;
|
|
}
|
|
|
|
/**
|
|
* Get node for configured search by name.
|
|
*
|
|
* @param configSearchName
|
|
* name of configured search for which to get node
|
|
* @return node reference for configured search
|
|
*/
|
|
public NodeRef getConfiguredSearches(String configSearchName)
|
|
{
|
|
NodeRef configSearchNodeRef = null;
|
|
|
|
// get the folder reference from the
|
|
// public searches location
|
|
NodeRef publicSearchesFolderRef = getPublicSearchesRef();
|
|
|
|
// read the content nodes under the folder
|
|
List<ChildAssociationRef> childRefs = getNodeService().getChildAssocs(
|
|
publicSearchesFolderRef, ContentModel.ASSOC_CONTAINS,
|
|
RegexQNamePattern.MATCH_ALL);
|
|
|
|
// return content node with name matching given configured search name
|
|
if (childRefs.size() != 0)
|
|
{
|
|
for (ChildAssociationRef ref : childRefs)
|
|
{
|
|
NodeRef childNodeRef = ref.getChildRef();
|
|
Node childNode = new Node(childNodeRef);
|
|
if (getDictionaryService().isSubClass(childNode.getType(),
|
|
ContentModel.TYPE_CONTENT))
|
|
{
|
|
String childNodeName = childNode.getName();
|
|
if (childNodeName.equals(configSearchName))
|
|
{
|
|
configSearchNodeRef = childNodeRef;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return configSearchNodeRef;
|
|
}
|
|
|
|
/**
|
|
* Create child element representing given AVM node and add to given parent
|
|
* element
|
|
*
|
|
* @param doc
|
|
* Document to which given parent element belongs
|
|
* @param parent
|
|
* parent element to add AVM node to as child element
|
|
* @param node
|
|
* AVM node to add as child node to given parent
|
|
* @param selectableTypes
|
|
* AVM node types which must be marked as selectable
|
|
* @param facesContent
|
|
* Faces context used to get file-type icon for given AVM node
|
|
*/
|
|
private void addAVMChildNodeToParentElement(org.w3c.dom.Document doc,
|
|
org.w3c.dom.Element parent, AVMNodeDescriptor node,
|
|
QName[] selectableTypes, FacesContext facesContext)
|
|
{
|
|
// create child node element to add to file picker data
|
|
org.w3c.dom.Element childNodeElement = doc.createElement("child-node");
|
|
childNodeElement.setAttribute("avmPath", node.getPath());
|
|
childNodeElement.setAttribute("webappRelativePath", AVMUtil
|
|
.getWebappRelativePath(node.getPath()));
|
|
childNodeElement.setAttribute("type", node.isDirectory() ? "directory"
|
|
: "file");
|
|
|
|
// Set image attribute on each child
|
|
// TODO (Glen): IS this the right image to set?
|
|
// originally from Ariel's code
|
|
childNodeElement.setAttribute("image",
|
|
(node.isDirectory() ? "/images/icons/space_small.gif" : Utils
|
|
.getFileTypeImage(facesContext, node.getName(), true)));
|
|
|
|
boolean selectable = false;
|
|
|
|
// set 'selectable' attribute on child node to mark whether node should
|
|
// be selectable in file picker or not
|
|
//
|
|
// TODO Ariel: faking this for now since i can't figure out how to
|
|
// efficiently get the type
|
|
// qname from the avmservice
|
|
for (final QName typeQName : selectableTypes)
|
|
{
|
|
selectable = selectable
|
|
|| (WCMModel.TYPE_AVM_FOLDER.equals(typeQName) && node
|
|
.isDirectory());
|
|
selectable = selectable
|
|
|| (WCMModel.TYPE_AVM_CONTENT.equals(typeQName) && !node
|
|
.isDirectory());
|
|
}
|
|
childNodeElement.setAttribute("selectable", Boolean.toString(selectable));
|
|
|
|
// append child node element to parent
|
|
parent.appendChild(childNodeElement);
|
|
}
|
|
}
|