diff --git a/config/alfresco/linkvalidation-service-context.xml b/config/alfresco/linkvalidation-service-context.xml
index f1fe27a0f0..abdcb4a5c8 100644
--- a/config/alfresco/linkvalidation-service-context.xml
+++ b/config/alfresco/linkvalidation-service-context.xml
@@ -266,7 +266,16 @@
-
+
+ ${linkvalidation.pollInterval}
+
+
+
+ ${linkvalidation.retryInterval}
+
+
+ ${linkvalidation.disableOnFail}
+
diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties
index ac613a56fe..a08b63b84c 100644
--- a/config/alfresco/repository.properties
+++ b/config/alfresco/repository.properties
@@ -226,21 +226,29 @@ system.people_container.childname=sys:people
system.workflow_container.childname=sys:workflow
# Are user names case sensitive?
-# ==============================
-#
-# NOTE: If you are using mysql you must have case sensitive collation
-#
-# You can do this when creating the alfresco database at the start
-# CREATE DATABASE alfresco CHARACTER SET utf8 COLLATE utf8_bin;
-# If you want to do this later this is a dump and load fix as it is done when the database, tables and columns are created.
-#
-# Must other databases are case sensitive by default.
-#
user.name.caseSensitive=false
# AVM Specific properties.
avm.remote.idlestream.timeout=30000
+# ################################## #
+# WCM Link Validation Configuration #
+# ################################## #
+#
+# Note: Link Validation is disabled by default (as per poll interval = 0)
+#
+# linkvalidation.pollInterval - Poll interval to check getLatestSnapshotID (in milliseconds), eg. 5000 for 5 sec interval
+# If pollInterval is 0, link validation is disabled.
+#
+# linkvalidation.retryInterval - Retry interval (Virtualization server is not accessible or an error has occurred
+# during link validation.
+#
+# linkvalidation.disableOnFail - If set to TRUE link validation service will be terminated if an error will be occurred.
+
+linkvalidation.pollInterval=0
+linkvalidation.retryInterval=120000
+linkvalidation.disableOnFail=false
+
# ECM content usages/quotas
system.usages.enabled=true
diff --git a/source/java/org/alfresco/repo/importer/ImporterBootstrap.java b/source/java/org/alfresco/repo/importer/ImporterBootstrap.java
index ead48fb615..96c006bd3b 100644
--- a/source/java/org/alfresco/repo/importer/ImporterBootstrap.java
+++ b/source/java/org/alfresco/repo/importer/ImporterBootstrap.java
@@ -83,9 +83,10 @@ public class ImporterBootstrap extends AbstractLifecycleBean
private static final Log logger = LogFactory.getLog(ImporterBootstrap.class);
private boolean logEnabled = false;
- // Dependencies
private boolean allowWrite = true;
private boolean useExistingStore = false;
+ private UUID_BINDING uuidBinding = null;
+ // Dependencies
private TransactionService transactionService;
private NamespaceService namespaceService;
private NodeService nodeService;
@@ -125,6 +126,19 @@ public class ImporterBootstrap extends AbstractLifecycleBean
this.useExistingStore = useExistingStore;
}
+ /**
+ * Set the behaviour for generating UUIDs in the import. Values are set by the
+ * {@link UUID_BINDING} enum and default to {@link UUID_BINDING#CREATE_NEW_WITH_UUID}.
+ *
+ * This setting overrides the UUID binding behaviour specified in the view properties.
+ *
+ * @param uuidBinding the UUID generation behaviour
+ */
+ public void setUuidBinding(UUID_BINDING uuidBinding)
+ {
+ this.uuidBinding = uuidBinding;
+ }
+
/**
* Sets the Transaction Service
*
@@ -420,18 +434,23 @@ public class ImporterBootstrap extends AbstractLifecycleBean
binding.setResourceBundle(bundle);
}
- String uuidBinding = bootstrapView.getProperty(VIEW_UUID_BINDING);
- if (uuidBinding != null && uuidBinding.length() > 0)
+ String viewUuidBinding = bootstrapView.getProperty(VIEW_UUID_BINDING);
+ if (viewUuidBinding != null && viewUuidBinding.length() > 0)
{
try
{
- binding.setUUIDBinding(UUID_BINDING.valueOf(UUID_BINDING.class, uuidBinding));
+ binding.setUUIDBinding(UUID_BINDING.valueOf(UUID_BINDING.class, viewUuidBinding));
}
catch(IllegalArgumentException e)
{
- throw new ImporterException("The value " + uuidBinding + " is an invalid uuidBinding");
+ throw new ImporterException("The value " + viewUuidBinding + " is an invalid uuidBinding");
}
- }
+ }
+ // Override the UUID binding with the bean's
+ if (this.uuidBinding != null)
+ {
+ binding.setUUIDBinding(this.uuidBinding);
+ }
// Now import...
ImporterProgress importProgress = null;
@@ -539,14 +558,13 @@ public class ImporterBootstrap extends AbstractLifecycleBean
private Properties configuration = null;
private ResourceBundle resourceBundle = null;
private Location bootstrapLocation = null;
+ /** by default, use create new strategy for bootstrap import */
+ private UUID_BINDING uuidBinding = UUID_BINDING.CREATE_NEW_WITH_UUID;
private static final String IMPORT_LOCATION_UUID = "bootstrap.location.uuid";
private static final String IMPORT_LOCATION_NODEREF = "bootstrap.location.noderef";
private static final String IMPORT_LOCATION_PATH = "bootstrap.location.path";
- // by default, use create new strategy for bootstrap import
- private UUID_BINDING uuidBinding = UUID_BINDING.CREATE_NEW_WITH_UUID;
-
/**
* Set Import Configuration
*
@@ -620,10 +638,6 @@ public class ImporterBootstrap extends AbstractLifecycleBean
return value;
}
- /*
- * (non-Javadoc)
- * @see org.alfresco.service.cmr.view.ImporterBinding#getUUIDBinding()
- */
public UUID_BINDING getUUIDBinding()
{
return uuidBinding;
@@ -639,19 +653,11 @@ public class ImporterBootstrap extends AbstractLifecycleBean
this.uuidBinding = uuidBinding;
}
- /*
- * (non-Javadoc)
- * @see org.alfresco.service.cmr.view.ImporterBinding#searchWithinTransaction()
- */
public boolean allowReferenceWithinTransaction()
{
return true;
}
- /*
- * (non-Javadoc)
- * @see org.alfresco.service.cmr.view.ImporterBinding#getExcludedClasses()
- */
public QName[] getExcludedClasses()
{
// Note: Do not exclude any classes, we want to import all
diff --git a/source/java/org/alfresco/repo/importer/ImporterComponentTest.java b/source/java/org/alfresco/repo/importer/ImporterComponentTest.java
index 7dc77e478a..6cd5ded04c 100644
--- a/source/java/org/alfresco/repo/importer/ImporterComponentTest.java
+++ b/source/java/org/alfresco/repo/importer/ImporterComponentTest.java
@@ -33,6 +33,7 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.view.Location;
+import org.alfresco.service.cmr.view.ImporterBinding.UUID_BINDING;
import org.alfresco.util.BaseSpringTest;
import org.alfresco.util.debug.NodeStoreInspector;
@@ -80,6 +81,54 @@ public class ImporterComponentTest extends BaseSpringTest
System.out.println(NodeStoreInspector.dumpNodeStore(nodeService, storeRef));
}
+ public void testImportWithUuidBinding() throws Exception
+ {
+ Location location = new Location(storeRef);
+
+ // First pass must succeed
+ InputStream test1 = getClass().getClassLoader().getResourceAsStream("org/alfresco/repo/importer/importercomponent_test.xml");
+ InputStreamReader testReader1 = new InputStreamReader(test1, "UTF-8");
+ try
+ {
+ importerService.importView(testReader1, location, null, new ImportTimerProgress());
+ }
+ finally
+ {
+ testReader1.close();
+ }
+ // Second pass must succeed (defaults to CREATE_NEW)
+ InputStream test2 = getClass().getClassLoader().getResourceAsStream("org/alfresco/repo/importer/importercomponent_test.xml");
+ InputStreamReader testReader2 = new InputStreamReader(test2, "UTF-8");
+ try
+ {
+ importerBootstrap.setUuidBinding(UUID_BINDING.CREATE_NEW_WITH_UUID);
+ importerService.importView(testReader2, location, null, new ImportTimerProgress());
+ }
+ finally
+ {
+ testReader2.close();
+ }
+ // Set the UUID binding to guarantee a failure
+ InputStream test3 = getClass().getClassLoader().getResourceAsStream("org/alfresco/repo/importer/importercomponent_test.xml");
+ InputStreamReader testReader3 = new InputStreamReader(test3, "UTF-8");
+ try
+ {
+ importerBootstrap.setUuidBinding(UUID_BINDING.THROW_ON_COLLISION);
+ importerService.importView(testReader3, location, null, new ImportTimerProgress());
+ fail("Failed to detected collision of UUID on import with THROW_ON_COLLISION");
+ }
+ catch (Throwable e)
+ {
+ // Expected
+ }
+ finally
+ {
+ importerBootstrap.setUuidBinding(UUID_BINDING.CREATE_NEW_WITH_UUID);
+ testReader3.close();
+ }
+ System.out.println(NodeStoreInspector.dumpNodeStore(nodeService, storeRef));
+ }
+
public void testBootstrap()
{
StoreRef bootstrapStoreRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
diff --git a/source/java/org/alfresco/repo/importer/importercomponent_test.xml b/source/java/org/alfresco/repo/importer/importercomponent_test.xml
index d5fd119201..eb794f2d37 100644
--- a/source/java/org/alfresco/repo/importer/importercomponent_test.xml
+++ b/source/java/org/alfresco/repo/importer/importercomponent_test.xml
@@ -22,6 +22,7 @@
+ 05efa5db-2817-4ada-a0dc-657db2b2a0ac
`¬¦!£$%^&()-_=+tnu0000[]{};'#@~,
testuser
testuser
diff --git a/source/java/org/alfresco/repo/jscript/RhinoScriptTest.java b/source/java/org/alfresco/repo/jscript/RhinoScriptTest.java
index faffe1e9a7..0ffc79ae0b 100644
--- a/source/java/org/alfresco/repo/jscript/RhinoScriptTest.java
+++ b/source/java/org/alfresco/repo/jscript/RhinoScriptTest.java
@@ -141,16 +141,11 @@ public class RhinoScriptTest extends TestCase
// try another script eval - this time a function call returning a result
result = cx.evaluateString(scope, "function f(x) {return x+1} f(7)", "TestJS2", 1, null);
- assertEquals(8.0, cx.toNumber(result));
- }
- catch (Throwable err)
- {
- err.printStackTrace();
- fail(err.getMessage());
+ assertEquals(8.0, Context.toNumber(result));
}
finally
{
- cx.exit();
+ Context.exit();
}
return null;
@@ -186,7 +181,7 @@ public class RhinoScriptTest extends TestCase
// evaluate script that touches the wrapped NodeRef
Object result = cx.evaluateString(scope, "obj = rootref.getId()", "TestJS3", 1, null);
- assertEquals(ref1.getId(), cx.toString(result));
+ assertEquals(ref1.getId(), Context.toString(result));
// wrap a scriptable Alfresco Node object - the Node object is a wrapper like TemplateNode
ScriptNode node1 = new ScriptNode(root, serviceRegistry, scope);
@@ -196,14 +191,9 @@ public class RhinoScriptTest extends TestCase
// evaluate scripts that perform methods on the wrapped Node
result = cx.evaluateString(scope, TESTSCRIPT1, "TestJS4", 1, null);
}
- catch (Throwable err)
- {
- err.printStackTrace();
- fail(err.getMessage());
- }
finally
{
- cx.exit();
+ Context.exit();
}
return null;
@@ -258,10 +248,8 @@ public class RhinoScriptTest extends TestCase
// test executing a script directly as a String
scriptService.executeScriptString("javascript", TESTSCRIPT1, model);
}
- catch (Throwable err)
+ finally
{
- err.printStackTrace();
- fail(err.getMessage());
}
return null;
@@ -311,10 +299,8 @@ public class RhinoScriptTest extends TestCase
// ensure aspect has been added via script
assertTrue(nodeService.hasAspect(childRef.getChildRef(), ContentModel.ASPECT_LOCKABLE));
}
- catch (Throwable err)
+ finally
{
- err.printStackTrace();
- fail(err.getMessage());
}
return null;
@@ -361,10 +347,8 @@ public class RhinoScriptTest extends TestCase
System.out.println("Result from TESTSCRIPT_CLASSPATH3: " + result.toString());
assertTrue((Boolean)result); // we know the result is a boolean
}
- catch (Throwable err)
+ finally
{
- err.printStackTrace();
- fail(err.getMessage());
}
return null;
diff --git a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java
index e209d91023..b20d4f8029 100644
--- a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java
+++ b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java
@@ -588,6 +588,26 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
{
value = new ContentData(null, MimetypeMap.EXTENSION_BINARY, 0L, "UTF-8");
}
+ else if (propertyTypeQName.equals(DataTypeDefinition.LOCALE))
+ {
+ value = Locale.CHINESE;
+ }
+ else if (propertyTypeQName.equals(DataTypeDefinition.BOOLEAN))
+ {
+ value = Boolean.TRUE;
+ }
+ else if (propertyTypeQName.equals(DataTypeDefinition.PATH))
+ {
+ value = new Path();
+ }
+ else if (propertyTypeQName.equals(DataTypeDefinition.QNAME))
+ {
+ value = TYPE_QNAME_EXTENDED_CONTENT;
+ }
+ else if (propertyTypeQName.equals(DataTypeDefinition.CATEGORY) || propertyTypeQName.equals(DataTypeDefinition.NODE_REF))
+ {
+ value = new NodeRef("workspace://SpacesStore/12345");
+ }
else
{
value = new Long(System.currentTimeMillis());
diff --git a/source/java/org/alfresco/repo/node/FullNodeServiceTest.java b/source/java/org/alfresco/repo/node/FullNodeServiceTest.java
index 8b7986f358..d7235e05fb 100644
--- a/source/java/org/alfresco/repo/node/FullNodeServiceTest.java
+++ b/source/java/org/alfresco/repo/node/FullNodeServiceTest.java
@@ -25,11 +25,14 @@
package org.alfresco.repo.node;
import java.io.Serializable;
+import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.node.db.DbNodeServiceImpl;
import org.alfresco.service.cmr.repository.MLText;
+import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.QName;
@@ -132,6 +135,75 @@ public class FullNodeServiceTest extends BaseNodeServiceTest
assertNull("Value returned is not null", mlText);
}
+ public void testMLValuesOnCreate() throws Exception
+ {
+ Map properties = new HashMap();
+ fillProperties(BaseNodeServiceTest.TYPE_QNAME_TEST_MANY_PROPERTIES, properties);
+ // Replace the MLText value with a plain string
+ properties.put(BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE, "Bonjour");
+ // Now switch to French
+ I18NUtil.setContentLocale(Locale.FRENCH);
+ // Create a node with the value
+ NodeRef nodeRef = nodeService.createNode(
+ rootNodeRef,
+ BaseNodeServiceTest.ASSOC_TYPE_QNAME_TEST_CHILDREN,
+ QName.createQName(BaseNodeServiceTest.NAMESPACE, getName()),
+ BaseNodeServiceTest.TYPE_QNAME_TEST_MANY_PROPERTIES,
+ properties).getChildRef();
+ // Now switch to English
+ I18NUtil.setContentLocale(Locale.ENGLISH);
+ // Set the english property
+ nodeService.setProperty(nodeRef, BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE, "Hello");
+
+ // Switch back to French and get the value
+ I18NUtil.setContentLocale(Locale.FRENCH);
+ assertEquals(
+ "Expected French value property",
+ "Bonjour",
+ nodeService.getProperty(nodeRef, BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE));
+
+ // Switch back to English and get the value
+ I18NUtil.setContentLocale(Locale.ENGLISH);
+ assertEquals(
+ "Expected English value property",
+ "Hello",
+ nodeService.getProperty(nodeRef, BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE));
+ }
+
+ public void testMLValuesOnAddAspect() throws Exception
+ {
+ Map properties = new HashMap();
+ fillProperties(BaseNodeServiceTest.TYPE_QNAME_TEST_MANY_PROPERTIES, properties);
+ // Replace the MLText value with a plain string
+ properties.put(BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE, "Bonjour");
+ // Now switch to French
+ I18NUtil.setContentLocale(Locale.FRENCH);
+ // Add an aspect
+ NodeRef nodeRef = rootNodeRef;
+ nodeService.addAspect(
+ nodeRef,
+ BaseNodeServiceTest.ASPECT_QNAME_TEST_TITLED,
+ properties);
+ // Now switch to English
+ I18NUtil.setContentLocale(Locale.ENGLISH);
+ // Set the english property
+ nodeService.setProperty(nodeRef, BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE, "Hello");
+
+ // Switch back to French and get the value
+ I18NUtil.setContentLocale(Locale.FRENCH);
+ assertEquals(
+ "Expected French value property",
+ "Bonjour",
+ nodeService.getProperty(nodeRef, BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE));
+
+ // Switch back to English and get the value
+ I18NUtil.setContentLocale(Locale.ENGLISH);
+ assertEquals(
+ "Expected English value property",
+ "Hello",
+ nodeService.getProperty(nodeRef, BaseNodeServiceTest.PROP_QNAME_ML_TEXT_VALUE));
+ }
+
/**
* {@inheritDoc}
*
diff --git a/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java b/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java
index 55470448b4..de2db3b9cd 100644
--- a/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java
+++ b/source/java/org/alfresco/repo/node/MLPropertyInterceptor.java
@@ -25,6 +25,7 @@
package org.alfresco.repo.node;
import java.io.Serializable;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
@@ -196,26 +197,20 @@ public class MLPropertyInterceptor implements MethodInterceptor
else if (methodName.equals("setProperties"))
{
NodeRef nodeRef = (NodeRef) args[0];
+ Map newProperties =(Map) args[1];
// Get the pivot translation, if appropriate
NodeRef pivotNodeRef = getPivotNodeRef(nodeRef);
- Map newProperties =(Map) args[1];
// Get the current properties for the node
Map currentProperties = nodeService.getProperties(nodeRef);
// Convert all properties
- Map convertedProperties = new HashMap(newProperties.size() * 2);
- for (Map.Entry entry : newProperties.entrySet())
- {
- QName propertyQName = entry.getKey();
- Serializable inboundValue = entry.getValue();
- // Get the current property value
- Serializable currentValue = currentProperties.get(propertyQName);
- // Convert the inbound property value
- inboundValue = convertInboundProperty(contentLocale, nodeRef, pivotNodeRef, propertyQName, inboundValue, currentValue);
- // Put the value into the map
- convertedProperties.put(propertyQName, inboundValue);
- }
+ Map convertedProperties = convertInboundProperties(
+ currentProperties,
+ newProperties,
+ contentLocale,
+ nodeRef,
+ pivotNodeRef);
// Now complete the call by passing the converted properties
nodeService.setProperties(nodeRef, convertedProperties);
// Done
@@ -236,6 +231,55 @@ public class MLPropertyInterceptor implements MethodInterceptor
nodeService.setProperty(nodeRef, propertyQName, inboundValue);
// Done
}
+ else if (methodName.equals("createNode") && args.length > 4)
+ {
+ NodeRef parentNodeRef = (NodeRef) args[0];
+ QName assocTypeQName = (QName) args[1];
+ QName assocQName = (QName) args[2];
+ QName nodeTypeQName = (QName) args[3];
+ Map newProperties =(Map) args[4];
+ if (newProperties == null)
+ {
+ newProperties = Collections.emptyMap();
+ }
+ NodeRef nodeRef = null; // Not created yet
+
+ // No pivot
+ NodeRef pivotNodeRef = null;
+
+ // Convert all properties
+ Map convertedProperties = convertInboundProperties(
+ null,
+ newProperties,
+ contentLocale,
+ nodeRef,
+ pivotNodeRef);
+ // Now complete the call by passing the converted properties
+ ret = nodeService.createNode(parentNodeRef, assocTypeQName, assocQName, nodeTypeQName, convertedProperties);
+ // Done
+ }
+ else if (methodName.equals("addAspect") && args[2] != null)
+ {
+ NodeRef nodeRef = (NodeRef) args[0];
+ QName aspectTypeQName = (QName) args[1];
+
+ // Get the pivot translation, if appropriate
+ NodeRef pivotNodeRef = getPivotNodeRef(nodeRef);
+
+ Map newProperties =(Map) args[2];
+ // Get the current properties for the node
+ Map currentProperties = nodeService.getProperties(nodeRef);
+ // Convert all properties
+ Map convertedProperties = convertInboundProperties(
+ currentProperties,
+ newProperties,
+ contentLocale,
+ nodeRef,
+ pivotNodeRef);
+ // Now complete the call by passing the converted properties
+ nodeService.addAspect(nodeRef, aspectTypeQName, convertedProperties);
+ // Done
+ }
else
{
ret = invocation.proceed();
@@ -328,6 +372,28 @@ public class MLPropertyInterceptor implements MethodInterceptor
return ret;
}
+ private Map convertInboundProperties(
+ Map currentProperties,
+ Map newProperties,
+ Locale contentLocale,
+ NodeRef nodeRef,
+ NodeRef pivotNodeRef)
+ {
+ Map convertedProperties = new HashMap(newProperties.size() * 2);
+ for (Map.Entry entry : newProperties.entrySet())
+ {
+ QName propertyQName = entry.getKey();
+ Serializable inboundValue = entry.getValue();
+ // Get the current property value
+ Serializable currentValue = currentProperties == null ? null : currentProperties.get(propertyQName);
+ // Convert the inbound property value
+ inboundValue = convertInboundProperty(contentLocale, nodeRef, pivotNodeRef, propertyQName, inboundValue, currentValue);
+ // Put the value into the map
+ convertedProperties.put(propertyQName, inboundValue);
+ }
+ return convertedProperties;
+ }
+
/**
*
* @param inboundValue The value that must be set
@@ -360,7 +426,7 @@ public class MLPropertyInterceptor implements MethodInterceptor
{
// This is a multilingual single-valued property
// Get the current value from the node service, if not provided
- if (currentValue == null)
+ if (currentValue == null && nodeRef != null)
{
currentValue = nodeService.getProperty(nodeRef, propertyQName);
}