mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-30 18:15:39 +00:00
36604: ALF-13745: Merged V3.4-BUG-FIX (3.4.10) to V4.0-BUG-FIX (4.0.3) 36602: ALF-13667 Additional OpenOffice mimetypes to be added to the mime-type maps - xls to pdf limit had been commented out - failover.transformer.PdfRenderer.PdfToImage and failover.transformer.PdfBox.PdfToImage should not have been been registered. Introduced an unregisteredBaseContentTransformer. In the case of these two transforms this would not have been a problem, as they were disable anyway due to EXPLICIT setting elsewhere. 36608: First part of ALF-14209 SOLR - does not support query for all stores - dynamic SOLR cores to track a store - NEW, DELETE, and change properties and reload 36635: ALF-13404 for documentlibrary-v2 APIs 36669: Fix issue with rendering multi-valued properties in JSON from server-side JS (from DaveD) 36676: Fix for ALF-14216 Solr Exception when you try to sort folders or files by size. 36692: Fix ALF-12966 - Comments doesn't work on iOS Safari. Anywhere TinyMCE is present does not work correctly e.g. comments, blogs, wiki, HTML content creation. 36693: ALF-14138: Prevent default Surf CMIS content WebScript clashing with Alfreco version (updated Surf libs r1081) 36714: ALF-14224: WorkflowTaskDefinition form-key fetching fixed for multi-instance UserTasks 36721: Fix for ALF-8374 - Simple view: incorrect file type icon for *.page and *.eps files 36726: Merged BRANCHES/DEV/V3.4-BUG-FIX to BRANCHES/DEV/V4.0-BUG-FIX 36724: Fix for ALF-14207 - cm:link not correctly handled in Share's doclist when users don't have permission 36728: Fix for ALF-14002: "No dashlets listed when customizing Site dashboard for the "Web Site Design Project" sample Share Site " 36732: Merged V3.4-BUG-FIX to V4.0-BUG-FIX 36637: ALF-6162 Thumbnail is not produced for PDFs encoded with JBIG2Decode << Reported problem still exists, but have made improvements see https://issues.alfresco.com/jira/browse/ALF-6162?focusedCommentId=162936&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-162936 >> - PDFRenderer now fails with an exception in more cases, rather than just silently continuing. Specific case was not handling JBig2 images. previously just resulted in a black box) - Handle the font family CIDFontType0 which includes HiddenHorzOCR 36640: ALF-13769: Merged BELARUS/DEV/V3.4-BUG-FIX-2012_05_04 to V3.4-BUG-FIX (3.4.10) 36440: ALF-11956: WCM accessibility Assignment of TinyMCE accessibility hotkeys only to activated RTE between multiple instances is added. Headings and some other related labels within the context of 'Create Web Content Wizard' were shortened and clarified. Fixed some issues related to hidden text for accessibility support in context of IE, which doesn't calculate styles and dimensions that are applied to elements before adding to DOM 36443: ALF-11956: WCM accessibility Added some changes missed in r36440 36645: ALF-13769: Merged DEV/V3.4-BUG-FIX-2012_01_10 to V3.4-BUG-FIX (3.4.10) 33381: ALF-10162: Web Form validation can be bypassed 1. New method was introduced to XFormsBean which allows it to validate the last inserted values. 2. CreateWebContentWizard finds XFormsBean in session and invokes isXformValid. If any validation errors exist it goes back and show the JSF error. 3. xform.js - contains code that removes JSF error as well as the XForms error. This is necessary because we need to clear the JSF error on the Javascript actions 4. container.jsp - includes a div wrapper with the id to be able unambiguously find the JSF error block. 36700: Merged DEV to V3.4-BUG-FIX (Reviewed by Erik) 36450: ALF-12261 : IE8 Specific: It's impossible add relationship type "Parent/Child" The type of the submit button should be set to 'button' in 'new-rmreference.get.html.ftl'. 36702: Merged DEV to V3.4-BUG-FIX (Reviewed by Erik) 36670: ALF-12825: Impossible choose the "Publication Date", the calendar isn't displayed The DatePicker component register a validation handler for the date entry field so that the submit button disables when an invalid date is entered. This handler register with the forms runtime instance. We should create this instance in FormUI_consructor, not is onReady method (form.js), because constructors always in order will be invoked. 36703: Fix for Mac Office 2011 Powerpoint save fails on CIFS. ALF-13615. 36733: Merged V4.0 to V4.0-BUG-FIX 36628: Added ${NOW} variable option for schema bootstrap scripts (see ALF-14174) 36632: Fix last part of ALF-14174: The patch adding timestamps to acl_change_set breaks SOLR tracking - Added ${NOW} to ACL change set timestamp when upgrading: commit_time_ms = ${NOW} 36647: ALF-14190: FSTR is not working - Due to someone updating dependencies without updating the build scripts! 36734: Merged V4.0 to V4.0-BUG-FIX (RECORD ONLY) 36605: ALF-13745: Merged V4.0-BUG-FIX (4.0.3) to V4.0 (4.0.2) 36604: ALF-13745: Merged V3.4-BUG-FIX (3.4.10) to V4.0-BUG-FIX (4.0.3) 36602: ALF-13667 Additional OpenOffice mimetypes to be added to the mime-type maps 36678: Merged BRANCHES/DEV/V4.0-BUG-FIX to BRANCHES/V4.0 36675: Fix for ALF-14216 Solr Exception when you try to sort folders or files by size. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@36737 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
571 lines
17 KiB
Java
571 lines
17 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.filesys.repo;
|
|
|
|
import java.io.FileNotFoundException;
|
|
import java.util.List;
|
|
|
|
import org.alfresco.jlan.server.filesys.FileAttribute;
|
|
import org.alfresco.jlan.server.filesys.FileInfo;
|
|
import org.alfresco.jlan.server.filesys.FileName;
|
|
import org.alfresco.jlan.server.filesys.FileType;
|
|
import org.alfresco.jlan.server.filesys.SearchContext;
|
|
import org.alfresco.jlan.server.filesys.pseudo.PseudoFile;
|
|
import org.alfresco.jlan.server.filesys.pseudo.PseudoFileList;
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
/**
|
|
* Wrapper for simple XPath searche against the node service. The search is performed statically
|
|
* outside the context instance itself - this class merely maintains the state of the search
|
|
* results across client connections.
|
|
*
|
|
* @author Derek Hulley
|
|
*/
|
|
public class ContentSearchContext extends SearchContext
|
|
implements InFlightCorrectable
|
|
{
|
|
// Debug logging
|
|
|
|
private static final Log logger = LogFactory.getLog(ContentSearchContext.class);
|
|
|
|
// Constants
|
|
//
|
|
// Link file size, actual size will be set if/when the link is opened
|
|
|
|
public final static int LinkFileSize = 512;
|
|
|
|
private InFlightCorrector corrector;
|
|
|
|
public void setInFlightCorrector(InFlightCorrector corrector)
|
|
{
|
|
this.corrector = corrector;
|
|
}
|
|
|
|
// List of nodes returned from the folder search
|
|
|
|
private CifsHelper cifsHelper;
|
|
private List<NodeRef> results;
|
|
private int index = -1;
|
|
|
|
// Pseudo file list blended into a wildcard folder search
|
|
|
|
private PseudoFileList pseudoList;
|
|
private boolean donePseudoFiles = false;
|
|
|
|
// Resume id
|
|
|
|
private int resumeId;
|
|
|
|
// Relative path being searched
|
|
|
|
private String m_relPath;
|
|
|
|
// Keep track of the last file name returned for fast restartAt processing
|
|
|
|
private String m_lastFileName;
|
|
|
|
/**
|
|
* Class constructor
|
|
*
|
|
* @param cifsHelper Filesystem helper class
|
|
* @param results List of file/folder nodes that match the search pattern
|
|
* @param searchStr Search path
|
|
* @param pseudoList List of pseudo files to be blended into the returned list of files
|
|
* @param relPath Relative path being searched
|
|
*/
|
|
protected ContentSearchContext(
|
|
CifsHelper cifsHelper,
|
|
List<NodeRef> results,
|
|
String searchStr,
|
|
PseudoFileList pseudoList,
|
|
String relPath)
|
|
{
|
|
super();
|
|
super.setSearchString(searchStr);
|
|
this.cifsHelper = cifsHelper;
|
|
this.results = results;
|
|
this.pseudoList = pseudoList;
|
|
|
|
m_relPath = relPath;
|
|
if ( m_relPath != null && m_relPath.endsWith( FileName.DOS_SEPERATOR_STR) == false)
|
|
m_relPath = m_relPath + FileName.DOS_SEPERATOR_STR;
|
|
}
|
|
|
|
/**
|
|
* Return the search as a string
|
|
*
|
|
* @return String
|
|
*/
|
|
public String toString()
|
|
{
|
|
StringBuilder sb = new StringBuilder(60);
|
|
|
|
sb.append("[ContentSearchContext searchStr=");
|
|
sb.append(getSearchString());
|
|
sb.append(", resultCount=");
|
|
sb.append(results.size());
|
|
sb.append(", pseudoList=");
|
|
if ( pseudoList != null)
|
|
sb.append( pseudoList.numberOfFiles());
|
|
else
|
|
sb.append("NULL");
|
|
sb.append("]");
|
|
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Return the resume id for the current file/directory in the search.
|
|
*
|
|
* @return int
|
|
*/
|
|
public int getResumeId()
|
|
{
|
|
return resumeId;
|
|
}
|
|
|
|
/**
|
|
* Determine if there are more files for the active search.
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public boolean hasMoreFiles()
|
|
{
|
|
// Pseudo files are returned first
|
|
|
|
if ( donePseudoFiles == false && pseudoList != null && index < (pseudoList.numberOfFiles() - 1))
|
|
return true;
|
|
return index < (results.size() - 1);
|
|
}
|
|
|
|
/**
|
|
* Return file information for the next file in the active search. Returns false if the search
|
|
* is complete.
|
|
*
|
|
* @param info FileInfo to return the file information.
|
|
* @return true if the file information is valid, else false
|
|
*/
|
|
public boolean nextFileInfo(FileInfo info)
|
|
{
|
|
// Check if there is anything else to return
|
|
|
|
if (!hasMoreFiles())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Increment the index and resume id
|
|
|
|
index++;
|
|
resumeId++;
|
|
|
|
// If the pseudo file list is valid return the pseudo files first
|
|
|
|
if ( donePseudoFiles == false && pseudoList != null)
|
|
{
|
|
if ( index < pseudoList.numberOfFiles())
|
|
{
|
|
PseudoFile pfile = pseudoList.getFileAt( index);
|
|
if ( pfile != null)
|
|
{
|
|
// Get the file information for the pseudo file
|
|
|
|
FileInfo pinfo = pfile.getFileInfo();
|
|
|
|
// Copy the file information to the callers file info
|
|
|
|
info.copyFrom( pinfo);
|
|
|
|
// Generate a file id for the current file
|
|
|
|
if ( info != null && info.getFileId() == -1)
|
|
{
|
|
StringBuilder pathStr = new StringBuilder( m_relPath);
|
|
pathStr.append ( info.getFileName());
|
|
|
|
info.setFileId( pathStr.toString().hashCode());
|
|
}
|
|
|
|
// Check if we have finished with the pseudo file list, switch to the normal file list
|
|
|
|
if ( index == (pseudoList.numberOfFiles() - 1))
|
|
{
|
|
// Switch to the main file list
|
|
|
|
donePseudoFiles = true;
|
|
index = -1;
|
|
}
|
|
|
|
// Indicate that the file information is valid
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return the next available file information for a real file/folder
|
|
|
|
try
|
|
{
|
|
// Loop until we get a valid node, might have been deleted since the initial folder search
|
|
|
|
ContentFileInfo nextInfo = null;
|
|
NodeRef nextNodeRef = null;
|
|
|
|
while ( nextInfo == null && index < results.size())
|
|
{
|
|
// Get the next node from the search
|
|
|
|
nextNodeRef = results.get(index);
|
|
|
|
try {
|
|
|
|
// Get the file information and copy across to the caller's file info
|
|
|
|
nextInfo = cifsHelper.getFileInformation(nextNodeRef, "", false, false);
|
|
info.copyFrom(nextInfo);
|
|
|
|
/**
|
|
* Apply in flight correction
|
|
*/
|
|
if(corrector != null)
|
|
{
|
|
corrector.correct(info, m_relPath);
|
|
}
|
|
|
|
}
|
|
catch ( InvalidNodeRefException ex) {
|
|
|
|
// Log a warning
|
|
|
|
if ( logger.isWarnEnabled())
|
|
{
|
|
logger.warn("Noderef " + nextNodeRef + " no longer valid, ignoring");
|
|
}
|
|
|
|
// Update the node index, node no longer exists, try the next node in the search
|
|
|
|
index++;
|
|
resumeId++;
|
|
}
|
|
}
|
|
|
|
// Check if we have finished returning file info
|
|
|
|
if ( nextInfo == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Generate a file id for the current file
|
|
|
|
StringBuilder pathStr = new StringBuilder( m_relPath);
|
|
pathStr.append ( info.getFileName());
|
|
|
|
// Set the file id
|
|
|
|
long id = DefaultTypeConverter.INSTANCE.convert(Long.class, cifsHelper.getNodeService().getProperty(nextNodeRef, ContentModel.PROP_NODE_DBID));
|
|
info.setFileId((int) (id & 0xFFFFFFFFL));
|
|
|
|
// Check if this is a link node
|
|
|
|
if ( nextInfo.isLinkNode())
|
|
{
|
|
// Set a dummy file size for the link data that will be generated if/when the file is opened
|
|
|
|
info.setFileSize( LinkFileSize);
|
|
|
|
// Make the link read-only
|
|
|
|
if ( info.isReadOnly() == false)
|
|
info.setFileAttributes( info.getFileAttributes() + FileAttribute.ReadOnly);
|
|
|
|
// Set the file type to indicate a symbolic link
|
|
|
|
info.setFileType( FileType.SymbolicLink);
|
|
}
|
|
else
|
|
info.setFileType( FileType.RegularFile);
|
|
|
|
// Keep track of the last file name returned
|
|
|
|
m_lastFileName = info.getFileName();
|
|
|
|
// Indicate that the file information is valid
|
|
|
|
return true;
|
|
}
|
|
catch (FileNotFoundException e)
|
|
{
|
|
}
|
|
|
|
// File information is not valid
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Return the file name of the next file in the active search. Returns null is the search is
|
|
* complete.
|
|
*
|
|
* @return String
|
|
*/
|
|
public String nextFileName()
|
|
{
|
|
// Check if there is anything else to return
|
|
|
|
if (!hasMoreFiles())
|
|
return null;
|
|
|
|
// Increment the index and resume id
|
|
|
|
index++;
|
|
resumeId++;
|
|
|
|
// If the pseudo file list is valid return the pseudo files first
|
|
|
|
if ( donePseudoFiles == false && pseudoList != null)
|
|
{
|
|
if ( index < pseudoList.numberOfFiles())
|
|
{
|
|
PseudoFile pfile = pseudoList.getFileAt( index);
|
|
if ( pfile != null)
|
|
{
|
|
// Get the file information for the pseudo file
|
|
|
|
FileInfo pinfo = pfile.getFileInfo();
|
|
|
|
// Copy the file information to the callers file info
|
|
|
|
return pinfo.getFileName();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Switch to the main file list
|
|
|
|
donePseudoFiles = true;
|
|
index = -1;
|
|
|
|
if ( results == null || results.size() == 0)
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Get the next file info from the node search
|
|
|
|
NodeRef nextNodeRef = results.get(index);
|
|
|
|
try
|
|
{
|
|
// Get the file information and copy across to the callers file info
|
|
|
|
FileInfo nextInfo = cifsHelper.getFileInformation(nextNodeRef, "", false, false);
|
|
|
|
// Keep track of the last file name returned
|
|
|
|
m_lastFileName = nextInfo.getFileName();
|
|
|
|
// Indicate that the file information is valid
|
|
|
|
return nextInfo.getFileName();
|
|
}
|
|
catch (FileNotFoundException e)
|
|
{
|
|
}
|
|
|
|
// No more files
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Restart a search at the specified resume point.
|
|
*
|
|
* @param resumeId Resume point id.
|
|
* @return true if the search can be restarted, else false.
|
|
*/
|
|
public boolean restartAt(FileInfo info)
|
|
{
|
|
// Check if the resume point is in the pseudo file list
|
|
|
|
int resId = 0;
|
|
|
|
if (pseudoList != null)
|
|
{
|
|
while ( resId < pseudoList.numberOfFiles())
|
|
{
|
|
// Check if the current pseudo file matches the resume file name
|
|
|
|
PseudoFile pfile = pseudoList.getFileAt(resId);
|
|
if ( pfile.getFileName().equals(info.getFileName()))
|
|
{
|
|
// Found the restart point
|
|
|
|
donePseudoFiles = false;
|
|
index = resId - 1;
|
|
|
|
return true;
|
|
}
|
|
else
|
|
resId++;
|
|
}
|
|
}
|
|
|
|
// Check if the resume file name is the last file returned
|
|
|
|
if ( m_lastFileName != null && info.getFileName().equalsIgnoreCase( m_lastFileName)) {
|
|
|
|
// Reset the index/resume id
|
|
|
|
index = index - 1;
|
|
resumeId = resumeId - 1;
|
|
donePseudoFiles = true;
|
|
|
|
// DEBUG
|
|
|
|
if ( logger.isDebugEnabled())
|
|
logger.debug("Fast search restart - " + m_lastFileName);
|
|
return true;
|
|
}
|
|
|
|
// Check if the resume file is in the main file list
|
|
|
|
if ( results != null)
|
|
{
|
|
int idx = 0;
|
|
|
|
while ( idx < results.size())
|
|
{
|
|
// Get the file name for the node
|
|
|
|
String fname = cifsHelper.getFileName( results.get( idx));
|
|
if ( fname != null && fname.equals( info.getFileName()))
|
|
{
|
|
index = idx - 1;
|
|
resumeId = resId - 1;
|
|
donePseudoFiles = true;
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
idx++;
|
|
resId++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Failed to find resume file
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Restart the current search at the specified file.
|
|
*
|
|
* @param info File to restart the search at.
|
|
* @return true if the search can be restarted, else false.
|
|
*/
|
|
public boolean restartAt(int resumeId)
|
|
{
|
|
// Resume ids are one based as zero has special meaning for some protocols, adjust the resume id
|
|
|
|
resumeId--;
|
|
|
|
// Check if the resume point is in the pseudo file list
|
|
|
|
if (pseudoList != null)
|
|
{
|
|
if ( resumeId < pseudoList.numberOfFiles())
|
|
{
|
|
// Resume at a pseudo file
|
|
|
|
index = resumeId;
|
|
donePseudoFiles = false;
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// Adjust the resume id so that it is an index into the main file list
|
|
|
|
resumeId -= pseudoList.numberOfFiles();
|
|
}
|
|
}
|
|
|
|
// Check if the resume point is valid
|
|
|
|
if ( results != null && resumeId < results.size())
|
|
{
|
|
index = resumeId;
|
|
donePseudoFiles = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Invalid resume point
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if the search is returning pseudo files or real file entries
|
|
*
|
|
* @return boolean
|
|
*/
|
|
protected boolean returningPseudoFiles() {
|
|
if ( pseudoList == null)
|
|
return false;
|
|
return donePseudoFiles ? false : true;
|
|
}
|
|
|
|
/**
|
|
* Return the relative path that is being searched
|
|
*
|
|
* @return String
|
|
*/
|
|
protected String getRelativePath() {
|
|
return m_relPath;
|
|
}
|
|
|
|
/**
|
|
* Return the results array size
|
|
*
|
|
* @return int
|
|
*/
|
|
protected int getResultsSize() {
|
|
return results != null ? results.size() : 0;
|
|
}
|
|
|
|
/**
|
|
* Return the pseudo file list size
|
|
*
|
|
* @return int
|
|
*/
|
|
protected int getPseudoListSize() {
|
|
return pseudoList != null ? pseudoList.numberOfFiles() : 0;
|
|
}
|
|
}
|