mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Merged V3.1 to HEAD
13484: ETHREEOH-1547: Do not set requiresNew flag and propagate exceptions in BaseDialogBean 13383: ETHREEOH-1220: Update LDAP-authentication-context to include allowGetEnabled entry to support Share 13381: ETHREEOH-1181: NTLM authentication periodically fails over CIFS - "Read-Write transaction started within read-only transaction" 13376: ETHREEOH-279: Friendly error message when cm:filename regular expression constraint is violated 13364: ETHREEOH-814: Correct character encoding issues in LDAP synchronization 13353: ETHREEOH-1444: Ability to run Alfresco from unexploded .war file with embedded license 13328: ETHREEOH-1400: Prevent TLD warnings on Weblogic startup 13183: Follow up to 13177: Fixes for Weblogic compatibility 13177: Fixes for Weblogic compatibility 13109: Build/test fix (to avoid unintentional import via application-context.xml) 13100: Checkpoint for new DM index check (enterprise-only) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13525 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -20,6 +20,9 @@
|
|||||||
<property name="allowDeleteUser">
|
<property name="allowDeleteUser">
|
||||||
<value>true</value>
|
<value>true</value>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="allowGetEnabled">
|
||||||
|
<value>true</value>
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@ d_dictionary.property.err.cannot_relax_mandatory_enforcement=Cannot relax mandat
|
|||||||
|
|
||||||
d_dictionary.constraint.regex.no_match=Value ''{0}'' does not match regular expression: {1}
|
d_dictionary.constraint.regex.no_match=Value ''{0}'' does not match regular expression: {1}
|
||||||
d_dictionary.constraint.regex.match=Value ''{0}'' matches regular expression: {1}
|
d_dictionary.constraint.regex.match=Value ''{0}'' matches regular expression: {1}
|
||||||
|
d_dictionary.constraint.regex.error.cm\:filename=Value ''{0}'' is not valid as a file name. This property must be a valid file name.
|
||||||
|
|
||||||
d_dictionary.constraint.numeric_range.invalid_min_value=Invalid 'minValue' property: {0}
|
d_dictionary.constraint.numeric_range.invalid_min_value=Invalid 'minValue' property: {0}
|
||||||
d_dictionary.constraint.numeric_range.invalid_max_value=Invalid 'maxValue' property: {0}
|
d_dictionary.constraint.numeric_range.invalid_max_value=Invalid 'maxValue' property: {0}
|
||||||
|
@@ -308,7 +308,7 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi
|
|||||||
{
|
{
|
||||||
// TODO Need to find out if this is important and if so
|
// TODO Need to find out if this is important and if so
|
||||||
// need to capture Transaction IDs.
|
// need to capture Transaction IDs.
|
||||||
return new NodeRef.Status("Unknown", !exists(nodeRef));
|
return new NodeRef.Status("Unknown", null, !exists(nodeRef));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -226,6 +226,24 @@ import org.springframework.beans.PropertyAccessException;
|
|||||||
throw new DictionaryException(ERR_PROPERTY_MISMATCH, e, namedValue.getName(), shortName);
|
throw new DictionaryException(ERR_PROPERTY_MISMATCH, e, namedValue.getName(), shortName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass in the name as a special property, if it is available
|
||||||
|
if (beanWrapper.isWritableProperty("_shortName"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
beanWrapper.setPropertyValue("_shortName", shortName);
|
||||||
|
}
|
||||||
|
catch (PropertyAccessException e)
|
||||||
|
{
|
||||||
|
throw new DictionaryException(ERR_PROPERTY_MISMATCH, e, shortName, shortName);
|
||||||
|
}
|
||||||
|
catch (InvalidPropertyException e)
|
||||||
|
{
|
||||||
|
throw new DictionaryException(ERR_PROPERTY_MISMATCH, e, shortName, shortName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// now initialize
|
// now initialize
|
||||||
constraint.initialize();
|
constraint.initialize();
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
* As a special exception to the terms and conditions of version 2.0 of
|
* 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
|
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||||
* FLOSS exception. You should have recieved a copy of the text describing
|
* FLOSS exception. You should have received a copy of the text describing
|
||||||
* the FLOSS exception, and it is also available here:
|
* the FLOSS exception, and it is also available here:
|
||||||
* http://www.alfresco.com/legal/licensing"
|
* http://www.alfresco.com/legal/licensing"
|
||||||
*/
|
*/
|
||||||
@@ -40,6 +40,31 @@ public abstract class AbstractConstraint implements Constraint
|
|||||||
{
|
{
|
||||||
public static final String ERR_PROP_NOT_SET = "d_dictionary.constraint.err.property_not_set";
|
public static final String ERR_PROP_NOT_SET = "d_dictionary.constraint.err.property_not_set";
|
||||||
public static final String ERR_EVALUATE_EXCEPTION = "d_dictionary.constraint.err.evaluate_exception";
|
public static final String ERR_EVALUATE_EXCEPTION = "d_dictionary.constraint.err.evaluate_exception";
|
||||||
|
|
||||||
|
|
||||||
|
/** The constraint name. May be useful in error messages */
|
||||||
|
private String shortName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the constraint name. Automatically called after construction. Please excuse the strange method name as we
|
||||||
|
* want the property name to begin with an underscore to avoid property name clashes.
|
||||||
|
*
|
||||||
|
* @param shortName
|
||||||
|
*/
|
||||||
|
public void set_shortName(String shortName)
|
||||||
|
{
|
||||||
|
this.shortName = shortName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the constraint name. May be useful in error messages.
|
||||||
|
*
|
||||||
|
* @return the constraint name.
|
||||||
|
*/
|
||||||
|
public String getShortName()
|
||||||
|
{
|
||||||
|
return this.shortName;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @see org.alfresco.service.cmr.dictionary.Constraint#getType()
|
* @see org.alfresco.service.cmr.dictionary.Constraint#getType()
|
||||||
|
@@ -29,6 +29,7 @@ import java.util.Map;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.alfresco.i18n.I18NUtil;
|
||||||
import org.alfresco.service.cmr.dictionary.ConstraintException;
|
import org.alfresco.service.cmr.dictionary.ConstraintException;
|
||||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||||
|
|
||||||
@@ -51,6 +52,7 @@ public class RegexConstraint extends AbstractConstraint
|
|||||||
{
|
{
|
||||||
public static final String CONSTRAINT_REGEX_NO_MATCH = "d_dictionary.constraint.regex.no_match";
|
public static final String CONSTRAINT_REGEX_NO_MATCH = "d_dictionary.constraint.regex.no_match";
|
||||||
public static final String CONSTRAINT_REGEX_MATCH = "d_dictionary.constraint.regex.match";
|
public static final String CONSTRAINT_REGEX_MATCH = "d_dictionary.constraint.regex.match";
|
||||||
|
public static final String CONSTRAINT_REGEX_MSG_PREFIX = "d_dictionary.constraint.regex.error.";
|
||||||
|
|
||||||
private String expression;
|
private String expression;
|
||||||
private Pattern patternMatcher;
|
private Pattern patternMatcher;
|
||||||
@@ -127,7 +129,14 @@ public class RegexConstraint extends AbstractConstraint
|
|||||||
boolean matches = matcher.matches();
|
boolean matches = matcher.matches();
|
||||||
if (matches != requiresMatch)
|
if (matches != requiresMatch)
|
||||||
{
|
{
|
||||||
if (requiresMatch)
|
// Look for a message corresponding to this constraint name
|
||||||
|
String messageId = CONSTRAINT_REGEX_MSG_PREFIX + getShortName();
|
||||||
|
if (I18NUtil.getMessage(messageId, value) != null)
|
||||||
|
{
|
||||||
|
throw new ConstraintException(messageId, value);
|
||||||
|
}
|
||||||
|
// Otherwise, fall back to a generic (but unfriendly) message
|
||||||
|
else if (requiresMatch)
|
||||||
{
|
{
|
||||||
throw new ConstraintException(RegexConstraint.CONSTRAINT_REGEX_NO_MATCH, value, expression);
|
throw new ConstraintException(RegexConstraint.CONSTRAINT_REGEX_NO_MATCH, value, expression);
|
||||||
}
|
}
|
||||||
|
@@ -27,8 +27,10 @@ package org.alfresco.repo.importer;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileWriter;
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -173,12 +175,12 @@ public class ExportSourceImporter implements ImporterJobSPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
File tempFile = TempFileProvider.createTempFile("ExportSourceImporter-", ".xml");
|
File tempFile = TempFileProvider.createTempFile("ExportSourceImporter-", ".xml");
|
||||||
Writer writer = new BufferedWriter(new FileWriter(tempFile));
|
Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tempFile), "UTF-8"));
|
||||||
XMLWriter xmlWriter = createXMLExporter(writer);
|
XMLWriter xmlWriter = createXMLExporter(writer);
|
||||||
exportSource.generateExport(xmlWriter);
|
exportSource.generateExport(xmlWriter);
|
||||||
xmlWriter.close();
|
xmlWriter.close();
|
||||||
|
|
||||||
Reader reader = new BufferedReader(new FileReader(tempFile));
|
Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(tempFile), "UTF-8"));
|
||||||
|
|
||||||
Location location = new Location(storeRef);
|
Location location = new Location(storeRef);
|
||||||
location.setPath(path);
|
location.setPath(path);
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -33,6 +33,7 @@ import org.alfresco.service.cmr.module.ModuleService;
|
|||||||
import org.alfresco.service.cmr.module.ModuleDetails;
|
import org.alfresco.service.cmr.module.ModuleDetails;
|
||||||
import org.alfresco.service.namespace.NamespaceService;
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.alfresco.util.ISO8601DateFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Place for general and miscellaneous utility functions not already found in generic JavaScript.
|
* Place for general and miscellaneous utility functions not already found in generic JavaScript.
|
||||||
@@ -126,4 +127,37 @@ public final class ScriptUtils extends BaseScopableProcessorExtension
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format timeInMillis to ISO 8601 formatted string
|
||||||
|
*
|
||||||
|
* @param timeInMillis
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String toISO8601(long timeInMillis)
|
||||||
|
{
|
||||||
|
return ISO8601DateFormat.format(new Date(timeInMillis));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format date to ISO 8601 formatted string
|
||||||
|
*
|
||||||
|
* @param date
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String toISO8601(Date date)
|
||||||
|
{
|
||||||
|
return ISO8601DateFormat.format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse date from ISO formatted string
|
||||||
|
*
|
||||||
|
* @param isoDateString
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Date fromISO8601(String isoDateString)
|
||||||
|
{
|
||||||
|
return ISO8601DateFormat.parse(isoDateString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -570,4 +570,10 @@ public interface NodeDaoService
|
|||||||
|
|
||||||
@DirtySessionAnnotation(markDirty=true)
|
@DirtySessionAnnotation(markDirty=true)
|
||||||
public void purgeTxn(Long txnId);
|
public void purgeTxn(Long txnId);
|
||||||
|
|
||||||
|
@DirtySessionAnnotation(markDirty=false)
|
||||||
|
public Long getMinTxnCommitTime();
|
||||||
|
|
||||||
|
@DirtySessionAnnotation(markDirty=false)
|
||||||
|
public Long getMaxTxnCommitTime();
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -672,6 +672,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
{
|
{
|
||||||
return new NodeRef.Status(
|
return new NodeRef.Status(
|
||||||
node.getTransaction().getChangeTxnId(),
|
node.getTransaction().getChangeTxnId(),
|
||||||
|
node.getTransaction().getId(),
|
||||||
node.getDeleted());
|
node.getDeleted());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -240,6 +240,12 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// started
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Reindex work started: " + this);
|
||||||
|
}
|
||||||
|
|
||||||
AuthenticationUtil.pushAuthentication();
|
AuthenticationUtil.pushAuthentication();
|
||||||
// authenticate as the system user
|
// authenticate as the system user
|
||||||
AuthenticationUtil.setRunAsUserSystem();
|
AuthenticationUtil.setRunAsUserSystem();
|
||||||
@@ -284,7 +290,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected enum InIndex
|
public enum InIndex
|
||||||
{
|
{
|
||||||
YES, NO, INDETERMINATE;
|
YES, NO, INDETERMINATE;
|
||||||
}
|
}
|
||||||
@@ -348,7 +354,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
* @param txn a specific transaction
|
* @param txn a specific transaction
|
||||||
* @return Returns <tt>true</tt> if the transaction is definitely in the index
|
* @return Returns <tt>true</tt> if the transaction is definitely in the index
|
||||||
*/
|
*/
|
||||||
protected InIndex isTxnPresentInIndex(final Transaction txn)
|
public InIndex isTxnPresentInIndex(final Transaction txn)
|
||||||
{
|
{
|
||||||
if (txn == null)
|
if (txn == null)
|
||||||
{
|
{
|
||||||
@@ -356,9 +362,9 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Long txnId = txn.getId();
|
final Long txnId = txn.getId();
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isTraceEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Checking for transaction in index: " + txnId);
|
logger.trace("Checking for transaction in index: " + txnId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the txn ID is present in any store's index
|
// Check if the txn ID is present in any store's index
|
||||||
@@ -398,6 +404,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
{
|
{
|
||||||
// There were deleted nodes only. Check that all the deleted nodes were
|
// There were deleted nodes only. Check that all the deleted nodes were
|
||||||
// removed from the index otherwise it is out of date.
|
// removed from the index otherwise it is out of date.
|
||||||
|
result = InIndex.YES;
|
||||||
for (StoreRef storeRef : storeRefs)
|
for (StoreRef storeRef : storeRefs)
|
||||||
{
|
{
|
||||||
if (!haveNodesBeenRemovedFromIndex(storeRef, txn))
|
if (!haveNodesBeenRemovedFromIndex(storeRef, txn))
|
||||||
@@ -444,17 +451,17 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
|
|
||||||
if (results.length() > 0)
|
if (results.length() > 0)
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isTraceEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Index has results for txn " + txnId + " for store " + storeRef);
|
logger.trace("Index has results for txn " + txnId + " for store " + storeRef);
|
||||||
}
|
}
|
||||||
return true; // there were updates/creates and results for the txn were found
|
return true; // there were updates/creates and results for the txn were found
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isTraceEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Transaction " + txnId + " not in index for store " + storeRef + ". Possibly out of date.");
|
logger.trace("Transaction " + txnId + " not in index for store " + storeRef + ". Possibly out of date.");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -474,9 +481,9 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
boolean foundNodeRef = false;
|
boolean foundNodeRef = false;
|
||||||
for (NodeRef nodeRef : nodeRefs)
|
for (NodeRef nodeRef : nodeRefs)
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isTraceEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Searching for node in index: \n" +
|
logger.trace("Searching for node in index: \n" +
|
||||||
" node: " + nodeRef + "\n" +
|
" node: " + nodeRef + "\n" +
|
||||||
" txn: " + txnId);
|
" txn: " + txnId);
|
||||||
}
|
}
|
||||||
@@ -514,9 +521,9 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No nodes found
|
// No nodes found
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isTraceEnabled())
|
||||||
{
|
{
|
||||||
logger.debug(" --> Node not found (OK)");
|
logger.trace(" --> Node not found (OK)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !foundNodeRef;
|
return !foundNodeRef;
|
||||||
|
@@ -1,18 +1,26 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2006 Alfresco, Inc.
|
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* Licensed under the Mozilla Public License version 1.1
|
* This program is free software; you can redistribute it and/or
|
||||||
* with a permitted attribution clause. You may obtain a
|
* modify it under the terms of the GNU General Public License
|
||||||
* copy of the License at
|
* as published by the Free Software Foundation; either version 2
|
||||||
*
|
* of the License, or (at your option) any later version.
|
||||||
* http://www.alfresco.org/legal/license.txt
|
|
||||||
*
|
* This program is distributed in the hope that it will be useful,
|
||||||
* Unless required by applicable law or agreed to in writing,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* software distributed under the License is distributed on an
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
* GNU General Public License for more details.
|
||||||
* either express or implied. See the License for the specific
|
|
||||||
* language governing permissions and limitations under the
|
* You should have received a copy of the GNU General Public License
|
||||||
* 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.repo.node.index;
|
package org.alfresco.repo.node.index;
|
||||||
|
|
||||||
@@ -56,6 +64,10 @@ public class IndexTransactionTracker extends AbstractReindexComponent
|
|||||||
private Map<Long, TxnRecord> voids;
|
private Map<Long, TxnRecord> voids;
|
||||||
private boolean forceReindex;
|
private boolean forceReindex;
|
||||||
|
|
||||||
|
private long fromTxnId;
|
||||||
|
private String statusMsg;
|
||||||
|
private static final String NO_REINDEX = "No reindex in progress";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the defaults.
|
* Set the defaults.
|
||||||
* <ul>
|
* <ul>
|
||||||
@@ -73,11 +85,16 @@ public class IndexTransactionTracker extends AbstractReindexComponent
|
|||||||
maxRecordSetSize = 1000;
|
maxRecordSetSize = 1000;
|
||||||
maxTransactionsPerLuceneCommit = 100;
|
maxTransactionsPerLuceneCommit = 100;
|
||||||
disableInTransactionIndexing = false;
|
disableInTransactionIndexing = false;
|
||||||
|
|
||||||
|
started = false;
|
||||||
previousTxnIds = Collections.<Long>emptyList();
|
previousTxnIds = Collections.<Long>emptyList();
|
||||||
lastMaxTxnId = Long.MAX_VALUE;
|
lastMaxTxnId = Long.MAX_VALUE;
|
||||||
fromTimeInclusive = -1L;
|
fromTimeInclusive = -1L;
|
||||||
voids = new TreeMap<Long, TxnRecord>();
|
voids = new TreeMap<Long, TxnRecord>();
|
||||||
forceReindex = false;
|
forceReindex = false;
|
||||||
|
|
||||||
|
fromTxnId = 0L;
|
||||||
|
statusMsg = NO_REINDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void setListener(IndexTransactionTrackerListener listener)
|
public synchronized void setListener(IndexTransactionTrackerListener listener)
|
||||||
@@ -177,12 +194,38 @@ public class IndexTransactionTracker extends AbstractReindexComponent
|
|||||||
return reindexInTransaction();
|
return reindexInTransaction();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public void reindexFromTxn(long txnId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logger.info("reindexFromTxn: "+txnId);
|
||||||
|
|
||||||
|
this.fromTxnId = txnId;
|
||||||
|
this.started = false;
|
||||||
|
|
||||||
|
reindex();
|
||||||
|
|
||||||
|
this.started = false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
this.fromTxnId = 0L;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void reindexImpl()
|
protected void reindexImpl()
|
||||||
{
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("reindexImpl started: " + this);
|
||||||
|
}
|
||||||
|
|
||||||
RetryingTransactionHelper retryingTransactionHelper = transactionService.getRetryingTransactionHelper();
|
RetryingTransactionHelper retryingTransactionHelper = transactionService.getRetryingTransactionHelper();
|
||||||
if (!started)
|
|
||||||
|
if ((!started) || (this.fromTxnId != 0L))
|
||||||
{
|
{
|
||||||
// Disable in-transaction indexing
|
// Disable in-transaction indexing
|
||||||
if (disableInTransactionIndexing && nodeIndexer != null)
|
if (disableInTransactionIndexing && nodeIndexer != null)
|
||||||
@@ -194,8 +237,29 @@ public class IndexTransactionTracker extends AbstractReindexComponent
|
|||||||
voids.clear();
|
voids.clear();
|
||||||
previousTxnIds = new ArrayList<Long>(maxRecordSetSize);
|
previousTxnIds = new ArrayList<Long>(maxRecordSetSize);
|
||||||
lastMaxTxnId = null; // So that it is ignored at first
|
lastMaxTxnId = null; // So that it is ignored at first
|
||||||
fromTimeInclusive = retryingTransactionHelper.doInTransaction(getStartingCommitTimeWork, true, true);
|
|
||||||
|
if (this.fromTxnId != 0L)
|
||||||
|
{
|
||||||
|
Long fromTxnCommitTime = getTxnCommitTime(this.fromTxnId);
|
||||||
|
|
||||||
|
if (fromTxnCommitTime == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fromTimeInclusive = fromTxnCommitTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fromTimeInclusive = retryingTransactionHelper.doInTransaction(getStartingCommitTimeWork, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
started = true;
|
started = true;
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("reindexImpl: fromTimeInclusive: "+fromTimeInclusive+" "+this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
@@ -209,7 +273,36 @@ public class IndexTransactionTracker extends AbstractReindexComponent
|
|||||||
}
|
}
|
||||||
// Wait for the asynchronous reindexing to complete
|
// Wait for the asynchronous reindexing to complete
|
||||||
waitForAsynchronousReindexing();
|
waitForAsynchronousReindexing();
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("reindexImpl: completed: " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
statusMsg = NO_REINDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Long getTxnCommitTime(final long txnId)
|
||||||
|
{
|
||||||
|
RetryingTransactionHelper retryingTransactionHelper = transactionService.getRetryingTransactionHelper();
|
||||||
|
|
||||||
|
RetryingTransactionCallback<Long> getTxnCommitTimeWork = new RetryingTransactionCallback<Long>()
|
||||||
|
{
|
||||||
|
public Long execute() throws Exception
|
||||||
|
{
|
||||||
|
Transaction txn = nodeDaoService.getTxnById(txnId);
|
||||||
|
if (txn != null)
|
||||||
|
{
|
||||||
|
return txn.getCommitTimeMs();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.warn("Txn not found: "+txnId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return retryingTransactionHelper.doInTransaction(getTxnCommitTimeWork, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns <tt>true</tt> if the reindex process can exit otherwise <tt>false</tt> if
|
* @return Returns <tt>true</tt> if the reindex process can exit otherwise <tt>false</tt> if
|
||||||
@@ -217,6 +310,8 @@ public class IndexTransactionTracker extends AbstractReindexComponent
|
|||||||
*/
|
*/
|
||||||
private boolean reindexInTransaction()
|
private boolean reindexInTransaction()
|
||||||
{
|
{
|
||||||
|
List<Transaction> txns = null;
|
||||||
|
|
||||||
long toTimeExclusive = System.currentTimeMillis() - reindexLagMs;
|
long toTimeExclusive = System.currentTimeMillis() - reindexLagMs;
|
||||||
|
|
||||||
// Check that the voids haven't been filled
|
// Check that the voids haven't been filled
|
||||||
@@ -232,7 +327,7 @@ public class IndexTransactionTracker extends AbstractReindexComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get next transactions to index
|
// get next transactions to index
|
||||||
List<Transaction> txns = getNextTransactions(fromTimeInclusive, toTimeExclusive, previousTxnIds);
|
txns = getNextTransactions(fromTimeInclusive, toTimeExclusive, previousTxnIds);
|
||||||
|
|
||||||
// If there are no transactions, then all the work is done
|
// If there are no transactions, then all the work is done
|
||||||
if (txns.size() == 0)
|
if (txns.size() == 0)
|
||||||
@@ -243,14 +338,15 @@ public class IndexTransactionTracker extends AbstractReindexComponent
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statusMsg = String.format(
|
||||||
|
"Reindexing batch of %d transactions from %s (txnId=%s)",
|
||||||
|
txns.size(),
|
||||||
|
(new Date(fromTimeInclusive)).toString(),
|
||||||
|
txns.isEmpty() ? "---" : txns.get(0).getId().toString());
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
String msg = String.format(
|
logger.debug(statusMsg);
|
||||||
"Reindexing %d transactions from %s (%s)",
|
|
||||||
txns.size(),
|
|
||||||
(new Date(fromTimeInclusive)).toString(),
|
|
||||||
txns.isEmpty() ? "---" : txns.get(0).getId().toString());
|
|
||||||
logger.debug(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reindex the transactions. Voids between the last set of transactions and this
|
// Reindex the transactions. Voids between the last set of transactions and this
|
||||||
@@ -299,6 +395,11 @@ public class IndexTransactionTracker extends AbstractReindexComponent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getReindexStatus()
|
||||||
|
{
|
||||||
|
return statusMsg;
|
||||||
|
}
|
||||||
|
|
||||||
private static final long ONE_HOUR_MS = 3600*1000;
|
private static final long ONE_HOUR_MS = 3600*1000;
|
||||||
/**
|
/**
|
||||||
* Find a transaction time to start indexing from (inclusive). The last recorded transaction by ID
|
* Find a transaction time to start indexing from (inclusive). The last recorded transaction by ID
|
||||||
|
@@ -35,7 +35,9 @@ import org.alfresco.error.AlfrescoRuntimeException;
|
|||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||||
import org.alfresco.repo.tenant.TenantService;
|
import org.alfresco.repo.tenant.TenantService;
|
||||||
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.security.PermissionService;
|
import org.alfresco.service.cmr.security.PermissionService;
|
||||||
@@ -165,7 +167,20 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetCurrentUserCallback callback = new SetCurrentUserCallback(userName);
|
SetCurrentUserCallback callback = new SetCurrentUserCallback(userName);
|
||||||
Authentication auth = transactionService.getRetryingTransactionHelper().doInTransaction(callback, transactionService.isReadOnly(), false);
|
Authentication auth;
|
||||||
|
// If the repository is read only, we have to settle for a read only transaction. Auto user creation will
|
||||||
|
// not be possible.
|
||||||
|
if (transactionService.isReadOnly())
|
||||||
|
{
|
||||||
|
auth = transactionService.getRetryingTransactionHelper().doInTransaction(callback, true, false);
|
||||||
|
}
|
||||||
|
// Otherwise, we want a writeable transaction, so if the current transaction is read only we set the
|
||||||
|
// requiresNew flag to true
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auth = transactionService.getRetryingTransactionHelper().doInTransaction(callback, false,
|
||||||
|
AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY);
|
||||||
|
}
|
||||||
if ((auth == null) || (callback.ae != null))
|
if ((auth == null) || (callback.ae != null))
|
||||||
{
|
{
|
||||||
throw callback.ae;
|
throw callback.ae;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -166,11 +166,13 @@ public final class NodeRef implements EntityRef, Serializable
|
|||||||
public static class Status
|
public static class Status
|
||||||
{
|
{
|
||||||
private final String changeTxnId;
|
private final String changeTxnId;
|
||||||
|
private final Long dbTxnId;
|
||||||
private final boolean deleted;
|
private final boolean deleted;
|
||||||
|
|
||||||
public Status(String changeTxnId, boolean deleted)
|
public Status(String changeTxnId, Long dbTxnId, boolean deleted)
|
||||||
{
|
{
|
||||||
this.changeTxnId = changeTxnId;
|
this.changeTxnId = changeTxnId;
|
||||||
|
this.dbTxnId = dbTxnId;
|
||||||
this.deleted = deleted;
|
this.deleted = deleted;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -181,11 +183,35 @@ public final class NodeRef implements EntityRef, Serializable
|
|||||||
return changeTxnId;
|
return changeTxnId;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
* @return Returns the db ID of the last transaction to change the node
|
||||||
|
*/
|
||||||
|
public Long getDbTxnId()
|
||||||
|
{
|
||||||
|
return dbTxnId;
|
||||||
|
}
|
||||||
|
/**
|
||||||
* @return Returns true if the node has been deleted, otherwise false
|
* @return Returns true if the node has been deleted, otherwise false
|
||||||
*/
|
*/
|
||||||
public boolean isDeleted()
|
public boolean isDeleted()
|
||||||
{
|
{
|
||||||
return deleted;
|
return deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// debug display string
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(50);
|
||||||
|
|
||||||
|
sb.append("Status[")
|
||||||
|
.append("changeTxnId=")
|
||||||
|
.append(changeTxnId)
|
||||||
|
.append(", dbTxnId=")
|
||||||
|
.append(dbTxnId)
|
||||||
|
.append(", deleted=")
|
||||||
|
.append(deleted)
|
||||||
|
.append("]");
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user