Merged V2.2 to HEAD

7653: Update and added deployment icons
   7655: Fixed multithreaded test case to handle case where threads can't get started due to lack of available DB connections.
   7657: AR-1903: Text attachments should be treated the same way as other attachments.
   7661: Fixed duplicate index creation for column that is also declared unique
   7662: Additional indexes related to permissions
   7664: Fixed query for specific property types
   7667: Used existing attachable aspect for email attachments - effectively reversing association direction.
   7682: Added AVM Console page to webapp (admin user protected)
   7683: Merged V2.1 to V2.2
      7642: Fix for WCM-949
      7668: Debugging output for getAPath(). Possible partial fix for LazyInitialization errors seen by some customers
      7672: Fixed sub optimal tree pruning in filesystem deployment


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8442 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley 2008-03-06 21:28:43 +00:00
parent ab80624ce0
commit ecb74c1447
19 changed files with 215 additions and 79 deletions

View File

@ -9,24 +9,29 @@
-- Please contact support@alfresco.com if you need assistance with the upgrade.
--
CREATE INDEX fk_alf_acl_entr ON alf_access_control_entry (acl_id);
CREATE INDEX fk_alf_ace_perm ON alf_access_control_entry (permission_id);
CREATE INDEX fk_alf_ace_auth ON alf_access_control_entry (authority_id);
CREATE INDEX fk_alf_ace_perm ON alf_access_control_entry (permission_id);
CREATE INDEX fk_alf_ace_ctx ON alf_access_control_entry (context_id);
CREATE INDEX fk_alf_attr_acl ON alf_attributes (acl_id);
CREATE INDEX fk_alf_acl_acs ON alf_access_control_list (acl_change_set);
CREATE INDEX fk_alf_aclm_acl ON alf_acl_member (acl_id);
CREATE INDEX fk_alf_aclm_ace ON alf_acl_member (ace_id);
CREATE INDEX fk_alf_adtf_src ON alf_audit_fact (audit_source_id);
CREATE INDEX fk_alf_adtf_date ON alf_audit_fact (audit_date_id);
CREATE INDEX fk_alf_adtf_conf ON alf_audit_fact (audit_conf_id);
CREATE INDEX fk_alf_auth_ext ON alf_auth_ext_keys (id);
CREATE INDEX fk_alf_autha_ali ON alf_authority_alias (alias_id);
CREATE INDEX fk_alf_autha_aut ON alf_authority_alias (auth_id);
CREATE INDEX fk_alf_ca_pnode ON alf_child_assoc (parent_node_id);
CREATE INDEX fk_alf_ca_tqn ON alf_child_assoc (type_qname_id);
CREATE INDEX fk_alf_ca_qn_ns ON alf_child_assoc (qname_ns_id);
CREATE INDEX fk_alf_ca_cnode ON alf_child_assoc (child_node_id);
CREATE INDEX fk_alf_gatt_att ON alf_global_attributes (attribute);
-- alf_global_attributes.attribute is declared unique. Indexes may automatically have been created.
CREATE INDEX fk_alf_gatt_att ON alf_global_attributes (attribute); -- (optional)
CREATE INDEX fk_alf_lent_att ON alf_list_attribute_entries (attribute_id);

View File

@ -7,6 +7,12 @@
-- Please contact support@alfresco.com if you need assistance with the upgrade.
--
-- Add index support for AVM
-- Ideally we would have the indirection in the index but it is too long for mysql
-- CREATE INDEX idx_avm_lyr_indn on avm_nodes (primary_indirection, indirection(128));
-- This matches the hibernate schema and should be good enough for the standard WCM use cases
CREATE INDEX idx_avm_lyr_indn on avm_nodes (primary_indirection);
CREATE TABLE alf_acl_change_set (
id BIGINT NOT NULL AUTO_INCREMENT,
version BIGINT NOT NULL,
@ -26,6 +32,7 @@ ALTER TABLE alf_access_control_list
ADD COLUMN acl_change_set BIGINT,
ADD COLUMN inherits_from BIGINT;
CREATE INDEX fk_alf_acl_acs ON alf_access_control_list (acl_change_set);
CREATE INDEX idx_pm_acl_inh ON alf_access_control_list (inherits, inherits_from);
ALTER TABLE alf_access_control_list ADD CONSTRAINT fk_alf_acl_acs FOREIGN KEY (acl_change_set) REFERENCES alf_acl_change_set (id);
UPDATE alf_access_control_list acl

View File

@ -214,6 +214,8 @@ cm_contentmodel.property.cm_categories.description=Categories
cm_contentmodel.aspect.cm_attachable.title=Attachable
cm_contentmodel.aspect.cm_attachable.description=Allows other repository objects to be attached
cm_contentmodel.association.cm_attachments.title=Attachments
cm_contentmodel.association.cm_attachments.description=Attached repository objects
cm_contentmodel.aspect.cm_emailed.title=Emailed
cm_contentmodel.aspect.cm_emailed.description=Emailed

View File

@ -9,6 +9,7 @@
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
<import uri="http://www.alfresco.org/model/system/1.0" prefix="sys"/>
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
<import uri="http://www.alfresco.org/model/emailserver/1.0" prefix="emailserver" />
</imports>
<aspects>
@ -44,6 +45,24 @@
</associations>
</aspect>
<aspect name="emailserver:attached">
<title>Attached</title>
<associations>
<association name="emailserver:attachment">
<title>Attachment</title>
<source>
<mandatory>true</mandatory>
<many>true</many>
</source>
<target>
<class>cm:content</class>
<mandatory>false</mandatory>
<many>false</many>
</target>
</association>
</associations>
</aspect>
</aspects>
</model>

View File

@ -34,24 +34,6 @@
<aspects>
<aspect name="emailserver:attached">
<title>Attached</title>
<associations>
<association name="emailserver:attachment">
<title>Attachment</title>
<source>
<mandatory>true</mandatory>
<many>true</many>
</source>
<target>
<class>cm:content</class>
<mandatory>false</mandatory>
<many>false</many>
</target>
</association>
</associations>
</aspect>
<aspect name="emailserver:emailed">
<title>Emailed</title>
<parent>cm:emailed</parent>

View File

@ -323,16 +323,10 @@ public abstract class AbstractEmailMessageHandler implements EmailMessageHandler
NodeRef attachmentNode = addContentNode(nodeService, folder, fileName);
// Remove 'attached' aspect so that we work with the document in its clean form
if (nodeService.hasAspect(attachmentNode, EmailServerModel.ASPECT_ATTACHED))
{
nodeService.removeAspect(attachmentNode, EmailServerModel.ASPECT_ATTACHED);
}
// Add attached aspect
nodeService.addAspect(attachmentNode, EmailServerModel.ASPECT_ATTACHED, null);
// Recreate the association
nodeService.createAssociation(attachmentNode, mainContentNode, EmailServerModel.ASSOC_ATTACHMENT);
nodeService.addAspect(mainContentNode, ContentModel.ASPECT_ATTACHABLE, null);
// Add the association
nodeService.createAssociation(mainContentNode, attachmentNode, ContentModel.ASSOC_ATTACHMENTS);
if (log.isDebugEnabled())
{

View File

@ -242,7 +242,7 @@ public class SubethaEmailMessage implements EmailMessage
else
{
// It's the body
addBody(messagePart);
addBody(bp);
}
}

View File

@ -210,6 +210,10 @@ public interface ContentModel
static final QName TYPE_LINK = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "link");
static final QName PROP_LINK_DESTINATION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "destination");
// attachable aspect
static final QName ASPECT_ATTACHABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "attachable");
static final QName ASSOC_ATTACHMENTS = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "attachments");
// email aspect
static final QName ASPECT_MAILED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "emailed");
static final QName PROP_SENTDATE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "sentdate");

View File

@ -41,6 +41,8 @@ import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.avm.VersionDescriptor;
import org.alfresco.service.cmr.avm.locking.AVMLock;
import org.alfresco.service.cmr.avm.locking.AVMLockingService;
import org.alfresco.service.cmr.avmsync.AVMDifference;
import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.service.namespace.QName;
@ -48,7 +50,9 @@ import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* An interactive console for the AVM repository.
*
* @author britt
* @author Gavin Cornwell
*/
public class AVMInterpreter
{
@ -62,6 +66,11 @@ public class AVMInterpreter
*/
private AVMSyncService fSyncService;
/**
* The locking service.
*/
private AVMLockingService fLockingService;
/**
* The reader for interaction.
*/
@ -83,6 +92,7 @@ public class AVMInterpreter
AVMInterpreter console = new AVMInterpreter();
console.setAvmService((AVMService)context.getBean("AVMService"));
console.setAvmSyncService((AVMSyncService)context.getBean("AVMSyncService"));
console.setAvmLockingService((AVMLockingService)context.getBean("AVMLockingService"));
BulkLoader loader = new BulkLoader();
loader.setAvmService((AVMService)context.getBean("AVMService"));
console.setBulkLoader(loader);
@ -116,6 +126,15 @@ public class AVMInterpreter
fSyncService = syncService;
}
/**
* Set the AVM locking service.
* @param lockService
*/
public void setAvmLockingService(AVMLockingService lockService)
{
fLockingService = lockService;
}
/**
* Set the bulk loader.
* @param loader
@ -409,6 +428,56 @@ public class AVMInterpreter
out.println(p.getKey() + ": " + p.getValue());
}
}
else if (command[0].equals("descnode"))
{
if (command.length != 3)
{
return "Syntax Error.";
}
String path = command[1];
AVMNodeDescriptor nodeDesc = fService.lookup(Integer.parseInt(command[2]), path);
if (nodeDesc == null)
{
return "Path Not Found.";
}
out.println(nodeDesc.toString());
out.println("isDirectory: " + nodeDesc.isDirectory());
out.println("isFile: " + nodeDesc.isFile());
out.println("isPrimary: " + nodeDesc.isPrimary());
out.println("isOpaque: " + nodeDesc.getOpacity());
out.println("creator: " + nodeDesc.getCreator());
out.println("owner: " + nodeDesc.getOwner());
out.println("lastModifier: " + nodeDesc.getLastModifier());
out.println("created: " + new Date(nodeDesc.getCreateDate()));
out.println("modified: " + new Date(nodeDesc.getModDate()));
out.println("lastAccess: " + new Date(nodeDesc.getAccessDate()));
// get lock information
String lockPath = path.substring(path.indexOf("/"));
String store = path.substring(0, path.indexOf(":"));
String mainStore = store;
if (store.indexOf("--") != -1)
{
mainStore = store.substring(0, store.indexOf("--"));
}
AVMLock lock = fLockingService.getLock(mainStore, lockPath);
out.print("lock: ");
if (lock != null)
{
out.print("store = ");
out.print(lock.getStore());
out.print(", owners = ");
out.println(lock.getOwners());
}
else
{
out.println("No locks found");
}
}
else if (command[0].equals("deletenodeproperty"))
{
if (command.length != 3)

View File

@ -1534,6 +1534,10 @@ public class AVMRepository
{
throw new AVMNotFoundException("Could not find node: " + desc);
}
if (fgLogger.isDebugEnabled())
{
fgLogger.debug("Getting A Path for: " + desc);
}
List<String> components = new ArrayList<String>();
return recursiveGetAPath(node, components);
}
@ -1700,11 +1704,19 @@ public class AVMRepository
AVMStore store = fAVMStoreDAO.getByRoot(node);
if (store != null)
{
if (fgLogger.isDebugEnabled())
{
fgLogger.debug("Found path in HEAD of: " + store.getName());
}
return new Pair<Integer, String>(-1, makePath(components, store.getName()));
}
VersionRoot vr = fVersionRootDAO.getByRoot(node);
if (vr != null)
{
if (fgLogger.isDebugEnabled())
{
fgLogger.debug("Found path in version " + vr.getVersionID() + " in: " + vr.getAvmStore().getName());
}
return new Pair<Integer, String>(vr.getVersionID(), makePath(components, vr.getAvmStore().getName()));
}
return null;
@ -1713,8 +1725,12 @@ public class AVMRepository
for (ChildEntry entry : entries)
{
String name = entry.getKey().getName();
if (fgLogger.isDebugEnabled())
{
fgLogger.debug("Found component: " + name);
}
components.add(name);
Pair<Integer, String> path = recursiveGetAPath(entry.getKey().getParent(), components);
Pair<Integer, String> path = recursiveGetAPath(AVMNodeUnwrapper.Unwrap(entry.getKey().getParent()), components);
if (path != null)
{
return path;

View File

@ -26,13 +26,16 @@ package org.alfresco.repo.avm;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.remote.ClientTicketHolder;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.avmsync.AVMDifference;
import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.service.cmr.remote.AVMRemote;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.util.Pair;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import junit.framework.TestCase;
@ -86,6 +89,18 @@ public class AVMTestRemote extends TestCase
fContext.close();
}
public void testGetAPath()
throws Exception
{
fAVMRemote.createStore("test2932");
fAVMRemote.createDirectory("test2932:/", "a");
fAVMRemote.createFile("test2932:/a", "foo.txt").close();
AVMNodeDescriptor found = fAVMRemote.lookup(-1, "test2932:/a/foo.txt");
Pair<Integer, String> path = fAVMRemote.getAPath(found);
assertEquals(path.getSecond(), "test2932:/a/foo.txt");
explorePaths("foo--admin:/");
}
/**
* Do a simple hello world test.
*/
@ -106,6 +121,22 @@ public class AVMTestRemote extends TestCase
}
}
public void explorePaths(String path)
throws Exception
{
Map<String, AVMNodeDescriptor> listing = fAVMRemote.getDirectoryListing(-1, path);
for (Map.Entry<String, AVMNodeDescriptor> entry : listing.entrySet())
{
Pair<Integer, String> childPath = fAVMRemote.getAPath(entry.getValue());
System.out.println(childPath);
if (entry.getValue().isDirectory())
{
explorePaths(entry.getValue().getPath());
}
}
}
/**
* Test reading and writing.
*/

View File

@ -94,7 +94,7 @@
it points at (true) or inheriting what it points at from its
container (false). -->
<property name="primaryIndirection"
column="primary_indirection" type="boolean"/>
column="primary_indirection" type="boolean" index="idx_avm_lyr_indn" />
<property name="opacity" column="opacity" type="boolean"/>
<!-- Map of names to DirectoryEntries. -->
</subclass>

View File

@ -948,15 +948,12 @@ public class DeploymentServiceImpl implements DeploymentService
// Source is a directory.
if (dst.getType() == FileType.DIR)
{
if (!dstPath.equals("/"))
{
service.setGuid(ticket, dstPath, src.getGuid());
}
String extendedPath = extendPath(dstPath, dst.getName());
if (!excluded(matcher, src.getPath(), extendedPath))
{
deployDirectoryPush(service, ticket, report, callbacks, version, src.getPath(), extendPath(dstPath, dst.getName()), matcher);
}
service.setGuid(ticket, extendedPath, src.getGuid());
src = null;
dst = null;
continue;

View File

@ -28,6 +28,7 @@ package org.alfresco.repo.deploy;
import java.io.File;
import org.alfresco.repo.avm.AVMServiceTestBase;
import org.alfresco.repo.avm.util.BulkLoader;
import org.alfresco.service.cmr.avm.deploy.DeploymentEvent;
import org.alfresco.service.cmr.avm.deploy.DeploymentReport;
import org.alfresco.service.cmr.avm.deploy.DeploymentService;
@ -42,6 +43,7 @@ import org.springframework.context.support.FileSystemXmlApplicationContext;
public class FSDeploymentTest extends AVMServiceTestBase
{
public void testBasic()
throws Exception
{
File log = new File("deplog");
log.mkdir();
@ -108,11 +110,20 @@ public class FSDeploymentTest extends AVMServiceTestBase
count++;
}
assertEquals(5, count);
}
catch (Exception e)
BulkLoader loader = new BulkLoader();
loader.setAvmService(fService);
loader.recursiveLoad("source/java/org/alfresco/repo/avm", "main:/");
report = service.deployDifferenceFS(-1, "main:/", "localhost", 44100, "Giles", "Watcher", "sampleTarget", matcher, false, false, false, null);
fService.removeNode("main:/avm/hibernate");
fService.getFileOutputStream("main:/avm/AVMServiceTest.java").close();
report = service.deployDifferenceFS(-1, "main:/", "localhost", 44100, "Giles", "Watcher", "sampleTarget", matcher, false, false, false, null);
count = 0;
for (DeploymentEvent event : report)
{
e.printStackTrace();
fail();
System.out.println(event);
count++;
}
assertEquals(4, count);
}
finally
{

View File

@ -691,17 +691,17 @@ public class PropertyValue implements Cloneable, Serializable
}
/**
* Given an actual type qualified name, returns the <tt>String</tt> that represents it in
* the database.
* Given an actual type qualified name, returns the <tt>int</tt> ordinal number
* that represents it in the database.
*
* @param typeQName the type qualified name
* @return Returns the <tt>String</tt> representation of the type,
* e.g. <b>CONTENT</b> for type <b>d:content</b>.
* @return Returns the <tt>int</tt> representation of the type,
* e.g. <b>CONTENT.getOrdinalNumber()</b> for type <b>d:content</b>.
*/
public static String getActualTypeString(QName typeQName)
public static int convertToTypeOrdinal(QName typeQName)
{
ValueType valueType = makeValueType(typeQName);
return valueType.toString();
return valueType.getOrdinalNumber();
}
@Override

View File

@ -158,18 +158,17 @@ public class QNameDAOTest extends TestCase
logger.debug("Failed to create QNameEntity. Might retry.", e);
throw e;
}
finally
{
// Notify the counter that this thread is done
logger.debug("Thread " + threadName + " is DONE");
doneLatch.countDown();
}
}
else
{
throw new RuntimeException("QName entity should not exist");
// In the case where the threads have to wait for database connections,
// it is quite possible that the entity was created as the ready latch
// is released after five seconds
}
assertNotNull("QName should now exist", qnameEntity);
// Notify the counter that this thread is done
logger.debug("Thread " + threadName + " is DONE");
doneLatch.countDown();
// Done
return qnameEntity;
}
@ -201,7 +200,7 @@ public class QNameDAOTest extends TestCase
// Let the threads go
startLatch.countDown();
// Wait for them all to be done (within limit of 10 seconds per thread)
doneLatch.await(threadCount * 10, TimeUnit.SECONDS);
doneLatch.await(threadCount, TimeUnit.SECONDS);
if (doneLatch.getCount() > 0)
{
fail("Still waiting for threads to finish");

View File

@ -451,8 +451,8 @@
node.properties prop
where
(
prop.actualType = :actualTypeString or
prop.actualType = 'SERIALIZABLE'
prop.actualType = :actualType or
prop.actualType = 9
) and
prop.persistedType != 0
</query>

View File

@ -54,9 +54,9 @@
<version column="version" name="version" type="long" />
<property name="inherits" column="inherits" type="boolean" not-null="true" />
<property name="inherits" column="inherits" type="boolean" not-null="true" index="idx_pm_acl_inh" />
<property name="inheritsFrom" column="inherits_from" type="long" not-null="false" />
<property name="inheritsFrom" column="inherits_from" type="long" not-null="false" index="idx_pm_acl_inh" />
<property name="type" column="type" type="int" not-null="true" />

View File

@ -1406,14 +1406,14 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
{
// get the in-database string representation of the actual type
QName typeQName = actualDataTypeDefinition.getName();
final String actualTypeString = PropertyValue.getActualTypeString(typeQName);
final int actualTypeOrdinalNumber = PropertyValue.convertToTypeOrdinal(typeQName);
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
Query query = session
.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_ACTUAL_TYPE)
.setString("actualTypeString", actualTypeString);
.setInteger("actualType", actualTypeOrdinalNumber);
return query.scroll(ScrollMode.FORWARD_ONLY);
}
};