Addition of Import references; allows...

- secondary child links (or multiple parents)
- update of existing items

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2171 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
David Caruana
2006-01-21 19:14:16 +00:00
parent ec7fb0067e
commit c0524bd3cc
10 changed files with 505 additions and 186 deletions

View File

@@ -46,6 +46,11 @@ public interface ImportNode
*/
public TypeDefinition getTypeDefinition();
/**
* @return is this a node reference
*/
public boolean isReference();
/**
* @return the node ref
*/

View File

@@ -378,7 +378,7 @@ public class ImporterBootstrap
/**
* Bootstrap Binding
*/
private class BootstrapBinding implements ImporterBinding
private static class BootstrapBinding implements ImporterBinding
{
private Properties configuration = null;
private ResourceBundle resourceBundle = null;
@@ -455,6 +455,16 @@ public class ImporterBootstrap
logger.debug("Created node " + nodeRef + " (child name: " + childName + ") within parent " + parentRef + " (association type: " + assocName + ")");
}
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImporterProgress#nodeLinked(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName)
*/
public void nodeLinked(NodeRef nodeRef, NodeRef parentRef, QName assocName, QName childName)
{
if (logger.isDebugEnabled())
logger.debug("Linked node " + nodeRef + " (child name: " + childName + ") within parent " + parentRef + " (association type: " + assocName + ")");
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.Progress#contentCreated(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
*/

View File

@@ -368,8 +368,11 @@ public class ImporterComponent
private ImporterBinding binding;
private ImporterProgress progress;
private ImportPackageHandler streamHandler;
private List<ImportedNodeRef> nodeRefs = new ArrayList<ImportedNodeRef>();
private NodeImporterStrategy importStrategy;
private UpdateExistingNodeImporterStrategy updateStrategy;
// Import tracking
private List<ImportedNodeRef> nodeRefs = new ArrayList<ImportedNodeRef>();
// Flush threshold
private int flushThreshold = 500;
@@ -392,6 +395,7 @@ public class ImporterComponent
this.progress = progress;
this.streamHandler = streamHandler;
this.importStrategy = createNodeImporterStrategy(binding == null ? null : binding.getUUIDBinding());
this.updateStrategy = new UpdateExistingNodeImporterStrategy();
}
/**
@@ -479,7 +483,15 @@ public class ImporterComponent
public NodeRef importNode(ImportNode context)
{
// import node
NodeRef nodeRef = importStrategy.importNode(context);
NodeRef nodeRef;
if (context.isReference())
{
nodeRef = linkNode(context);
}
else
{
nodeRef = importStrategy.importNode(context);
}
// apply aspects
for (QName aspect : context.getNodeAspects())
@@ -512,6 +524,55 @@ public class ImporterComponent
return nodeRef;
}
/**
* Link an existing Node
*
* @param context node to link in
* @return node reference of child linked in
*/
private NodeRef linkNode(ImportNode context)
{
ImportParent parentContext = context.getParentContext();
NodeRef parentRef = parentContext.getParentRef();
// determine the child node reference
String uuid = context.getUUID();
if (uuid == null)
{
throw new ImporterException("Node reference does not resolve to a node");
}
NodeRef childRef = new NodeRef(parentRef.getStoreRef(), uuid);
// Note: do not link references that are defined in the root of the import
if (!parentRef.equals(getRootRef()))
{
// determine child assoc type
QName assocType = getAssocType(context);
// determine child name
QName childQName = getChildName(context);
if (childQName == null)
{
String name = (String)nodeService.getProperty(childRef, ContentModel.PROP_NAME);
if (name == null || name.length() == 0)
{
throw new ImporterException("Cannot determine node reference child name");
}
String localName = QName.createValidLocalName(name);
childQName = QName.createQName(assocType.getNamespaceURI(), localName);
}
// create the link
nodeService.addChild(parentRef, childRef, assocType, childQName);
reportNodeLinked(childRef, parentRef, assocType, childQName);
}
// second, perform any specified udpates to the node
updateStrategy.importNode(context);
return childRef;
}
/**
* Import Node Content.
* <p>
@@ -625,11 +686,7 @@ public class ImporterComponent
{
for (QName disabledBehaviour: disabledBehaviours)
{
boolean alreadyDisabled = behaviourFilter.disableBehaviour(importedRef.context.getNodeRef(), disabledBehaviour);
if (alreadyDisabled)
{
disabledBehaviours.remove(disabledBehaviour);
}
behaviourFilter.disableBehaviour(importedRef.context.getNodeRef(), disabledBehaviour);
}
nodeService.setProperty(importedRef.context.getNodeRef(), importedRef.property, nodeRef);
}
@@ -649,6 +706,40 @@ public class ImporterComponent
behaviourFilter.enableAllBehaviours();
}
/**
* Get the child name to import node under
*
* @param context the node
* @return the child name
*/
private QName getChildName(ImportNode context)
{
QName assocType = getAssocType(context);
QName childQName = null;
// Determine child name
String childName = context.getChildName();
if (childName != null)
{
childName = bindPlaceHolder(childName, binding);
String[] qnameComponents = QName.splitPrefixedQName(childName);
childQName = QName.createQName(qnameComponents[0], QName.createValidLocalName(qnameComponents[1]), namespaceService);
}
else
{
Map<QName, Serializable> typeProperties = context.getProperties();
String name = (String)typeProperties.get(ContentModel.PROP_NAME);
if (name != null && name.length() > 0)
{
name = bindPlaceHolder(name, binding);
String localName = QName.createValidLocalName(name);
childQName = QName.createQName(assocType.getNamespaceURI(), localName);
}
}
return childQName;
}
/**
* Get appropriate child association type for node to import under
*
@@ -845,6 +936,20 @@ public class ImporterComponent
}
}
/**
* Helper to report node linked progress
*
* @param progress
* @param childAssocRef
*/
private void reportNodeLinked(NodeRef childRef, NodeRef parentRef, QName assocType, QName childName)
{
if (progress != null)
{
progress.nodeLinked(childRef, parentRef, assocType, childName);
}
}
/**
* Helper to report content created progress
*
@@ -938,28 +1043,10 @@ public class ImporterComponent
TypeDefinition nodeType = node.getTypeDefinition();
NodeRef parentRef = node.getParentContext().getParentRef();
QName assocType = getAssocType(node);
QName childQName = null;
// Determine child name
String childName = node.getChildName();
if (childName != null)
QName childQName = getChildName(node);
if (childQName == null)
{
childName = bindPlaceHolder(childName, binding);
String[] qnameComponents = QName.splitPrefixedQName(childName);
childQName = QName.createQName(qnameComponents[0], QName.createValidLocalName(qnameComponents[1]), namespaceService);
}
else
{
Map<QName, Serializable> typeProperties = node.getProperties();
String name = (String)typeProperties.get(ContentModel.PROP_NAME);
if (name == null || name.length() == 0)
{
throw new ImporterException("Cannot import node of type " + nodeType.getName() + " - it does not have a name");
}
name = bindPlaceHolder(name, binding);
String localName = QName.createValidLocalName(name);
childQName = QName.createQName(assocType.getNamespaceURI(), localName);
throw new ImporterException("Cannot determine child name of node (type: " + nodeType.getName() + ")");
}
// Create initial node (but, first disable behaviour for the node to be created)
@@ -1154,8 +1241,11 @@ public class ImporterComponent
// do the update
Map<QName, Serializable> existingProperties = nodeService.getProperties(existingNodeRef);
Map<QName, Serializable> updateProperties = bindProperties(node);
if (updateProperties != null)
{
existingProperties.putAll(updateProperties);
nodeService.setProperties(existingNodeRef, existingProperties);
}
// Apply permissions
boolean inheritPermissions = node.getInheritPermissions();

View File

@@ -59,7 +59,6 @@ public class ImporterComponentTest extends BaseSpringTest
this.storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
}
@Override
protected void onTearDownInTransaction() throws Exception
{
@@ -98,6 +97,12 @@ public class ImporterComponentTest extends BaseSpringTest
" (association " + assocName + ")");
}
public void nodeLinked(NodeRef nodeRef, NodeRef parentRef, QName assocName, QName childName)
{
System.out.println("TestProgress: linked node " + nodeRef + " within parent " + parentRef + " named " + childName +
" (association " + assocName + ")");
}
public void contentCreated(NodeRef nodeRef, String sourceUrl)
{
System.out.println("TestProgress: created content " + nodeRef + " from url " + sourceUrl);

View File

@@ -4,7 +4,7 @@
<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
xmlns:cm="http://www.alfresco.org/model/content/1.0"
xmlns="">
xmlns:sys="http://www.alfresco.org/model/system/1.0">
<view:metadata>
<view:exportBy>unknown</view:exportBy>
@@ -13,7 +13,7 @@
<view:exportOf>/system</view:exportOf>
</view:metadata>
<cm:systemfolder view:childName="system">
<cm:systemfolder view:childName="system" view:id="the root system folder">
<cm:name>System</cm:name>
<cm:orderedchildren>true</cm:orderedchildren>
<cm:contains>
@@ -32,7 +32,7 @@
</view:properties>
<view:associations>
<cm:contains>
<cm:person view:childName="cm:fredb">
<cm:person view:childName="cm:fredb" view:id="fred">
<view:aspects/>
<view:properties>
<cm:userName>${username}</cm:userName>
@@ -45,30 +45,45 @@
</view:associations>
</cm:systemfolder>
<cm:systemfolder view:childName="cm:people shortcut">
<cm:contains>
<!-- create a secondary child link using a reference -->
<view:reference view:idref="fred" view:childName="fred shortcut">
<!-- Note: references can be updated/appended by specifying the usual property,
association and aspect sub-elements -->
<view:properties>
<cm:middleName>Raymond</cm:middleName>
</view:properties>
</view:reference>
</cm:contains>
</cm:systemfolder>
<!-- note: if no explicit view:childName, take from name if one exists -->
<cm:cmobject>
<cm:translatable/>
<cm:generalclassifiable/>
<cm:name>Some Content</cm:name>
<cm:name>Categorised Content</cm:name>
<cm:categories>
<view:value>../cm:people_x0020_folder</view:value>
<view:value>../cm:people_x0020_folder</view:value>
</cm:categories>
<cm:translations view:idref="xyz"/>
</cm:cmobject>
<cm:cmobject view:id="xyz">
<cm:name>Translation of Some Content</cm:name>
<cm:creator></cm:creator>
</cm:cmobject>
<cm:content>
<cm:name>Real content</cm:name>
<cm:content>contentUrl=classpath:org/alfresco/repo/importer/importercomponent_testfile.txt|mimetype=text|size=|encoding=</cm:content>
</cm:content>
</cm:contains>
</cm:systemfolder>
<cm:content view:id="some content">
<cm:name>Some content</cm:name>
<cm:content>contentUrl=classpath:org/alfresco/repo/importer/importercomponent_testfile.txt|mimetype=text|size=|encoding=</cm:content>
</cm:content>
<view:reference view:idref="the root system folder">
<view:associations>
<cm:contains>
<view:reference view:idref="some content" view:childName="link to some content"/>
</cm:contains>
</view:associations>
</view:reference>
</view:view>

View File

@@ -51,8 +51,10 @@ public class NodeContext extends ElementContext
implements ImportNode
{
private ParentContext parentContext;
private boolean isReference = false;
private NodeRef nodeRef;
private String uuid;
private String importId; // unique identifier within import (optional)
private String uuid; // unique identifier within repository
private TypeDefinition typeDef;
private String childName;
private Map<QName, AspectDefinition> nodeAspects = new HashMap<QName, AspectDefinition>();
@@ -96,6 +98,23 @@ public class NodeContext extends ElementContext
return typeDef;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#isReference()
*/
public boolean isReference()
{
return isReference;
}
/**
* @param isReference true => this is a node reference
*/
public void setReference(boolean isReference)
{
this.isReference = isReference;
}
/**
* Set Type Definition
*
@@ -139,6 +158,23 @@ public class NodeContext extends ElementContext
this.uuid = uuid;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#getImportId()
*/
public String getImportId()
{
return importId;
}
/**
* @param importId import scoped id
*/
public void setImportId(String importId)
{
this.importId = importId;
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#getChildName()
*/
@@ -369,11 +405,14 @@ public class NodeContext extends ElementContext
PropertyDefinition def = null;
if (nodeProperties.containsKey(defName) == false)
{
def = getDictionaryService().getProperty(typeDef.getName(), defName);
def = (typeDef == null) ? null : getDictionaryService().getProperty(typeDef.getName(), defName);
if (def == null)
{
Set<AspectDefinition> allAspects = new HashSet<AspectDefinition>();
if (typeDef != null)
{
allAspects.addAll(typeDef.getDefaultAspects());
}
allAspects.addAll(nodeAspects.values());
for (AspectDefinition aspectDef : allAspects)
{

View File

@@ -84,7 +84,10 @@ public class ParentContext extends ElementContext
{
this(elementName, parent);
// Ensure association is valid for node
TypeDefinition typeDef = parent.getTypeDefinition();
if (typeDef != null)
{
// Ensure association type is valid for node parent
Set<QName> allAspects = new HashSet<QName>();
for (AspectDefinition typeAspect : parent.getTypeDefinition().getDefaultAspects())
{
@@ -97,6 +100,7 @@ public class ParentContext extends ElementContext
{
throw new ImporterException("Association " + childDef.getName() + " is not valid for node " + parent.getTypeDefinition().getName());
}
}
parentRef = parent.getNodeRef();
assocType = childDef.getName();

View File

@@ -18,18 +18,21 @@ package org.alfresco.repo.importer.view;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import org.alfresco.repo.importer.Importer;
import org.alfresco.repo.importer.Parser;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.view.ImporterException;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.view.ImporterException;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
@@ -55,6 +58,8 @@ public class ViewParser implements Parser
private static final String VIEW_ISNULL_ATTR = "isNull";
private static final String VIEW_INHERIT_PERMISSIONS_ATTR = "inherit";
private static final String VIEW_ACCESS_STATUS_ATTR = "access";
private static final String VIEW_ID_ATTR = "id";
private static final String VIEW_IDREF_ATTR = "idref";
private static final QName VIEW_METADATA = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "metadata");
private static final QName VIEW_VALUE_QNAME = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "value");
private static final QName VIEW_VALUES_QNAME = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "values");
@@ -65,6 +70,7 @@ public class ViewParser implements Parser
private static final QName VIEW_ACE = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "ace");
private static final QName VIEW_AUTHORITY = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "authority");
private static final QName VIEW_PERMISSION = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "permission");
private static final QName VIEW_REFERENCE = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "reference");
// XML Pull Parser Factory
@@ -74,6 +80,15 @@ public class ViewParser implements Parser
private NamespaceService namespaceService;
private DictionaryService dictionaryService;
// Parser Context maintained during each parse
private class ParserContext
{
Importer importer;
DictionaryService dictionaryService;
Stack<ElementContext> elementStack;
Map<String, NodeRef> importIds = new HashMap<String, NodeRef>();
}
/**
* Construct
@@ -92,6 +107,7 @@ public class ViewParser implements Parser
}
}
/**
* @param namespaceService the namespace service
*/
@@ -117,7 +133,11 @@ public class ViewParser implements Parser
{
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(viewReader);
Stack<ElementContext> contextStack = new Stack<ElementContext>();
ParserContext parserContext = new ParserContext();
parserContext.importer = importer;
parserContext.dictionaryService = dictionaryService;
parserContext.elementStack = new Stack<ElementContext>();
try
{
@@ -129,17 +149,17 @@ public class ViewParser implements Parser
{
if (xpp.getDepth() == 1)
{
processRoot(xpp, importer, contextStack);
processRoot(xpp, parserContext);
}
else
{
processStartElement(xpp, contextStack);
processStartElement(xpp, parserContext);
}
break;
}
case XmlPullParser.END_TAG:
{
processEndElement(xpp, contextStack);
processEndElement(xpp, parserContext);
break;
}
}
@@ -164,46 +184,53 @@ public class ViewParser implements Parser
* @throws XmlPullParserException
* @throws IOException
*/
private void processStartElement(XmlPullParser xpp, Stack<ElementContext> contextStack)
private void processStartElement(XmlPullParser xpp, ParserContext parserContext)
throws XmlPullParserException, IOException
{
// Extract qualified name
QName defName = getName(xpp);
// Process the element
Object context = contextStack.peek();
Object element = parserContext.elementStack.peek();
// Handle special view directives
if (defName.equals(VIEW_METADATA))
{
contextStack.push(new MetaDataContext(defName, (ElementContext)context));
parserContext.elementStack.push(new MetaDataContext(defName, (ElementContext)element));
}
else if (defName.equals(VIEW_ASPECTS) || defName.equals(VIEW_PROPERTIES) || defName.equals(VIEW_ASSOCIATIONS) || defName.equals(VIEW_ACL))
{
if (context instanceof NodeItemContext)
if (element instanceof NodeItemContext)
{
throw new ImporterException("Cannot nest element " + defName + " within " + ((NodeItemContext)context).getElementName());
throw new ImporterException("Cannot nest element " + defName + " within " + ((NodeItemContext)element).getElementName());
}
if (!(context instanceof NodeContext))
if (!(element instanceof NodeContext))
{
throw new ImporterException("Element " + defName + " can only be declared within a node");
}
NodeContext nodeContext = (NodeContext)context;
contextStack.push(new NodeItemContext(defName, nodeContext));
NodeContext node = (NodeContext)element;
parserContext.elementStack.push(new NodeItemContext(defName, node));
// process ACL specific attributes
if (defName.equals(VIEW_ACL))
{
processACL(xpp, contextStack);
processACL(xpp, parserContext);
}
}
else
{
if (context instanceof MetaDataContext)
if (element instanceof MetaDataContext)
{
processMetaData(xpp, defName, contextStack);
processMetaData(xpp, defName, parserContext);
}
else if (context instanceof ParentContext)
else if (element instanceof ParentContext)
{
if (defName.equals(VIEW_REFERENCE))
{
// Process reference
processStartReference(xpp, defName, parserContext);
}
else
{
// Process type definition
TypeDefinition typeDef = dictionaryService.getType(defName);
@@ -211,14 +238,15 @@ public class ViewParser implements Parser
{
throw new ImporterException("Type " + defName + " has not been defined in the Repository dictionary");
}
processStartType(xpp, typeDef, contextStack);
processStartType(xpp, typeDef, parserContext);
}
return;
}
else if (context instanceof NodeContext)
else if (element instanceof NodeContext)
{
// Process children of node
// Note: Process in the following order: aspects, properties and associations
Object def = ((NodeContext)context).determineDefinition(defName);
Object def = ((NodeContext)element).determineDefinition(defName);
if (def == null)
{
throw new ImporterException("Definition " + defName + " is not valid; cannot find in Repository dictionary");
@@ -226,17 +254,17 @@ public class ViewParser implements Parser
if (def instanceof AspectDefinition)
{
processAspect(xpp, (AspectDefinition)def, contextStack);
processAspect(xpp, (AspectDefinition)def, parserContext);
return;
}
else if (def instanceof PropertyDefinition)
{
processProperty(xpp, ((PropertyDefinition)def).getName(), contextStack);
processProperty(xpp, ((PropertyDefinition)def).getName(), parserContext);
return;
}
else if (def instanceof ChildAssociationDefinition)
{
processStartChildAssoc(xpp, (ChildAssociationDefinition)def, contextStack);
processStartChildAssoc(xpp, (ChildAssociationDefinition)def, parserContext);
return;
}
else
@@ -244,38 +272,42 @@ public class ViewParser implements Parser
// TODO: general association
}
}
else if (context instanceof NodeItemContext)
else if (element instanceof NodeItemContext)
{
NodeItemContext nodeItemContext = (NodeItemContext)context;
NodeContext nodeContext = nodeItemContext.getNodeContext();
QName itemName = nodeItemContext.getElementName();
NodeItemContext nodeItem = (NodeItemContext)element;
NodeContext node = nodeItem.getNodeContext();
QName itemName = nodeItem.getElementName();
if (itemName.equals(VIEW_ASPECTS))
{
AspectDefinition def = nodeContext.determineAspect(defName);
AspectDefinition def = node.determineAspect(defName);
if (def == null)
{
throw new ImporterException("Aspect name " + defName + " is not valid; cannot find in Repository dictionary");
}
processAspect(xpp, def, contextStack);
processAspect(xpp, def, parserContext);
}
else if (itemName.equals(VIEW_PROPERTIES))
{
// Note: Allow properties which do not have a data dictionary definition
processProperty(xpp, defName, contextStack);
processProperty(xpp, defName, parserContext);
}
else if (itemName.equals(VIEW_ASSOCIATIONS))
{
// TODO: Handle general associations...
ChildAssociationDefinition def = (ChildAssociationDefinition)nodeContext.determineAssociation(defName);
AssociationDefinition def = (AssociationDefinition)node.determineAssociation(defName);
if (def == null)
{
throw new ImporterException("Association name " + defName + " is not valid; cannot find in Repository dictionary");
}
processStartChildAssoc(xpp, def, contextStack);
// TODO: Handle general associations...
if (!(def instanceof ChildAssociationDefinition))
{
throw new ImporterException("Unsupported operation: The association " + defName + " cannot be imported - only child associations are supported at this time");
}
processStartChildAssoc(xpp, (ChildAssociationDefinition)def, parserContext);
}
else if (itemName.equals(VIEW_ACL))
{
processAccessControlEntry(xpp, contextStack);
processAccessControlEntry(xpp, parserContext);
}
}
}
@@ -293,14 +325,14 @@ public class ViewParser implements Parser
* @throws XmlPullParserException
* @throws IOException
*/
private void processRoot(XmlPullParser xpp, Importer importer, Stack<ElementContext> contextStack)
private void processRoot(XmlPullParser xpp, ParserContext parserContext)
throws XmlPullParserException, IOException
{
ParentContext parentContext = new ParentContext(getName(xpp), dictionaryService, importer);
contextStack.push(parentContext);
ParentContext parent = new ParentContext(getName(xpp), parserContext.dictionaryService, parserContext.importer);
parserContext.elementStack.push(parent);
if (logger.isDebugEnabled())
logger.debug(indentLog("Pushed " + parentContext, contextStack.size() -1));
logger.debug(indentLog("Pushed " + parent, parserContext.elementStack.size() -1));
}
/**
@@ -312,10 +344,10 @@ public class ViewParser implements Parser
* @throws XmlPullParserException
* @throws IOException
*/
private void processMetaData(XmlPullParser xpp, QName metaDataName, Stack<ElementContext> contextStack)
private void processMetaData(XmlPullParser xpp, QName metaDataName, ParserContext parserContext)
throws XmlPullParserException, IOException
{
MetaDataContext context = (MetaDataContext)contextStack.peek();
MetaDataContext metaData = (MetaDataContext)parserContext.elementStack.peek();
String value = null;
@@ -331,7 +363,7 @@ public class ViewParser implements Parser
throw new ImporterException("Meta data element " + metaDataName + " is missing end tag");
}
context.setProperty(metaDataName, value);
metaData.setProperty(metaDataName, value);
}
/**
@@ -343,23 +375,86 @@ public class ViewParser implements Parser
* @throws XmlPullParserException
* @throws IOException
*/
private void processStartType(XmlPullParser xpp, TypeDefinition typeDef, Stack<ElementContext> contextStack)
private void processStartType(XmlPullParser xpp, TypeDefinition typeDef, ParserContext parserContext)
throws XmlPullParserException, IOException
{
ParentContext parentContext = (ParentContext)contextStack.peek();
NodeContext context = new NodeContext(typeDef.getName(), parentContext, typeDef);
ParentContext parent = (ParentContext)parserContext.elementStack.peek();
NodeContext node = new NodeContext(typeDef.getName(), parent, typeDef);
// Extract child name if explicitly defined
String childName = xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_CHILD_NAME_ATTR);
if (childName != null && childName.length() > 0)
{
context.setChildName(childName);
node.setChildName(childName);
}
contextStack.push(context);
// Extract import id if explicitly defined
String importId = xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_ID_ATTR);
if (importId != null && importId.length() > 0)
{
node.setImportId(importId);
}
parserContext.elementStack.push(node);
if (logger.isDebugEnabled())
logger.debug(indentLog("Pushed " + context, contextStack.size() -1));
logger.debug(indentLog("Pushed " + node, parserContext.elementStack.size() -1));
}
/**
* Process start reference
*
* @param xpp
* @param typeDef
* @param contextStack
* @throws XmlPullParserException
* @throws IOException
*/
private void processStartReference(XmlPullParser xpp, QName refName, ParserContext parserContext)
throws XmlPullParserException, IOException
{
ParentContext parent = (ParentContext)parserContext.elementStack.peek();
// Extract Import scoped reference Id if explicitly defined
String uuid = null;
String idRef = xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_IDREF_ATTR);
if (idRef != null && idRef.length() > 0)
{
// retrieve uuid from previously imported node
NodeRef nodeRef = getImportReference(parserContext, idRef);
if (nodeRef == null)
{
throw new ImporterException("Cannot find node referenced by id " + idRef);
}
uuid = nodeRef.getId();
}
// Create reference
NodeContext node = new NodeContext(refName, parent, null);
node.setReference(true);
if (uuid != null)
{
node.setUUID(uuid);
}
// Extract child name if explicitly defined
String childName = xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_CHILD_NAME_ATTR);
if (childName != null && childName.length() > 0)
{
node.setChildName(childName);
}
// Extract import id if explicitly defined
String importId = xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_ID_ATTR);
if (importId != null && importId.length() > 0)
{
node.setImportId(importId);
}
parserContext.elementStack.push(node);
if (logger.isDebugEnabled())
logger.debug(indentLog("Pushed Reference " + node, parserContext.elementStack.size() -1));
}
/**
@@ -371,11 +466,11 @@ public class ViewParser implements Parser
* @throws XmlPullParserException
* @throws IOException
*/
private void processAspect(XmlPullParser xpp, AspectDefinition aspectDef, Stack<ElementContext> contextStack)
private void processAspect(XmlPullParser xpp, AspectDefinition aspectDef, ParserContext parserContext)
throws XmlPullParserException, IOException
{
NodeContext context = peekNodeContext(contextStack);
context.addAspect(aspectDef);
NodeContext node = peekNodeContext(parserContext.elementStack);
node.addAspect(aspectDef);
int eventType = xpp.next();
if (eventType != XmlPullParser.END_TAG)
@@ -384,7 +479,7 @@ public class ViewParser implements Parser
}
if (logger.isDebugEnabled())
logger.debug(indentLog("Processed aspect " + aspectDef.getName(), contextStack.size()));
logger.debug(indentLog("Processed aspect " + aspectDef.getName(), parserContext.elementStack.size()));
}
/**
@@ -393,9 +488,9 @@ public class ViewParser implements Parser
* @param xpp
* @param contextStack
*/
private void processACL(XmlPullParser xpp, Stack<ElementContext> contextStack)
private void processACL(XmlPullParser xpp, ParserContext parserContext)
{
NodeContext context = peekNodeContext(contextStack);
NodeContext node = peekNodeContext(parserContext.elementStack);
String strInherit = xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_INHERIT_PERMISSIONS_ATTR);
if (strInherit != null)
@@ -403,7 +498,7 @@ public class ViewParser implements Parser
Boolean inherit = Boolean.valueOf(strInherit);
if (!inherit)
{
context.setInheritPermissions(false);
node.setInheritPermissions(false);
}
}
}
@@ -416,10 +511,10 @@ public class ViewParser implements Parser
* @throws XmlPullParserException
* @throws IOException
*/
private void processAccessControlEntry(XmlPullParser xpp, Stack<ElementContext> contextStack)
private void processAccessControlEntry(XmlPullParser xpp, ParserContext parserContext)
throws XmlPullParserException, IOException
{
NodeContext context = peekNodeContext(contextStack);
NodeContext node = peekNodeContext(parserContext.elementStack);
QName defName = getName(xpp);
if (!defName.equals(VIEW_ACE))
@@ -500,7 +595,7 @@ public class ViewParser implements Parser
}
// update node context
context.addAccessControlEntry(accessStatus, authority, permission);
node.addAccessControlEntry(accessStatus, authority, permission);
}
/**
@@ -512,10 +607,10 @@ public class ViewParser implements Parser
* @throws XmlPullParserException
* @throws IOException
*/
private void processProperty(XmlPullParser xpp, QName propertyName, Stack<ElementContext> contextStack)
private void processProperty(XmlPullParser xpp, QName propertyName, ParserContext parserContext)
throws XmlPullParserException, IOException
{
NodeContext context = peekNodeContext(contextStack);
NodeContext node = peekNodeContext(parserContext.elementStack);
// Extract single value
String value = "";
@@ -527,11 +622,10 @@ public class ViewParser implements Parser
}
if (eventType == XmlPullParser.END_TAG)
{
context.addProperty(propertyName, value);
node.addProperty(propertyName, value);
}
else
{
// Extract collection, if specified
boolean isCollection = false;
if (eventType == XmlPullParser.START_TAG)
@@ -539,7 +633,7 @@ public class ViewParser implements Parser
QName name = getName(xpp);
if (name.equals(VIEW_VALUES_QNAME))
{
context.addPropertyCollection(propertyName);
node.addPropertyCollection(propertyName);
isCollection = true;
eventType = xpp.next();
if (eventType == XmlPullParser.TEXT)
@@ -568,10 +662,10 @@ public class ViewParser implements Parser
}
if (eventType == XmlPullParser.END_TAG)
{
context.addProperty(propertyName, decoratedValue);
node.addProperty(propertyName, decoratedValue);
if (datatype != null)
{
context.addDatatype(propertyName, dictionaryService.getDataType(datatype));
node.addDatatype(propertyName, dictionaryService.getDataType(datatype));
}
}
else
@@ -604,11 +698,10 @@ public class ViewParser implements Parser
throw new ImporterException("Invalid view structure - property " + propertyName + " definition is invalid");
}
}
}
if (logger.isDebugEnabled())
logger.debug(indentLog("Processed property " + propertyName, contextStack.size()));
logger.debug(indentLog("Processed property " + propertyName, parserContext.elementStack.size()));
}
/**
@@ -620,24 +713,18 @@ public class ViewParser implements Parser
* @throws XmlPullParserException
* @throws IOException
*/
private void processStartChildAssoc(XmlPullParser xpp, ChildAssociationDefinition childAssocDef, Stack<ElementContext> contextStack)
private void processStartChildAssoc(XmlPullParser xpp, ChildAssociationDefinition childAssocDef, ParserContext parserContext)
throws XmlPullParserException, IOException
{
NodeContext context = peekNodeContext(contextStack);
if (context.getNodeRef() == null)
{
// Create Node
NodeRef nodeRef = context.getImporter().importNode(context);
context.setNodeRef(nodeRef);
}
NodeContext node = peekNodeContext(parserContext.elementStack);
importNode(parserContext, node);
// Construct Child Association Context
ParentContext parentContext = new ParentContext(childAssocDef.getName(), context, childAssocDef);
contextStack.push(parentContext);
ParentContext parent = new ParentContext(childAssocDef.getName(), node, childAssocDef);
parserContext.elementStack.push(parent);
if (logger.isDebugEnabled())
logger.debug(indentLog("Pushed " + parentContext, contextStack.size() -1));
logger.debug(indentLog("Pushed " + parent, parserContext.elementStack.size() -1));
}
/**
@@ -646,28 +733,28 @@ public class ViewParser implements Parser
* @param xpp
* @param contextStack
*/
private void processEndElement(XmlPullParser xpp, Stack<ElementContext> contextStack)
private void processEndElement(XmlPullParser xpp, ParserContext parserContext)
{
ElementContext context = contextStack.peek();
if (context.getElementName().getLocalName().equals(xpp.getName()) &&
context.getElementName().getNamespaceURI().equals(xpp.getNamespace()))
ElementContext element = parserContext.elementStack.peek();
if (element.getElementName().getLocalName().equals(xpp.getName()) &&
element.getElementName().getNamespaceURI().equals(xpp.getNamespace()))
{
context = contextStack.pop();
element = parserContext.elementStack.pop();
if (logger.isDebugEnabled())
logger.debug(indentLog("Popped " + context, contextStack.size()));
logger.debug(indentLog("Popped " + element, parserContext.elementStack.size()));
if (context instanceof NodeContext)
if (element instanceof NodeContext)
{
processEndType((NodeContext)context);
processEndType(parserContext, (NodeContext)element);
}
else if (context instanceof ParentContext)
else if (element instanceof ParentContext)
{
processEndChildAssoc((ParentContext)context);
processEndChildAssoc(parserContext, (ParentContext)element);
}
else if (context instanceof MetaDataContext)
else if (element instanceof MetaDataContext)
{
processEndMetaData((MetaDataContext)context);
processEndMetaData(parserContext, (MetaDataContext)element);
}
}
}
@@ -675,17 +762,13 @@ public class ViewParser implements Parser
/**
* Process end of the type definition
*
* @param context
* @param node
*/
private void processEndType(NodeContext context)
private void processEndType(ParserContext parserContext, NodeContext node)
{
NodeRef nodeRef = context.getNodeRef();
if (nodeRef == null)
{
nodeRef = context.getImporter().importNode(context);
context.setNodeRef(nodeRef);
}
context.getImporter().childrenImported(nodeRef);
NodeRef nodeRef = node.getNodeRef();
importNode(parserContext, node);
node.getImporter().childrenImported(nodeRef);
}
/**
@@ -693,7 +776,7 @@ public class ViewParser implements Parser
*
* @param context
*/
private void processEndChildAssoc(ParentContext context)
private void processEndChildAssoc(ParserContext parserContext, ParentContext parent)
{
}
@@ -702,11 +785,61 @@ public class ViewParser implements Parser
*
* @param context
*/
private void processEndMetaData(MetaDataContext context)
private void processEndMetaData(ParserContext parserContext, MetaDataContext context)
{
context.getImporter().importMetaData(context.getProperties());
}
/**
* Import node
*
* @param parserContext parser context
* @param node node context
*/
private void importNode(ParserContext parserContext, NodeContext node)
{
if (node.getNodeRef() == null)
{
// Import Node
NodeRef nodeRef = node.getImporter().importNode(node);
node.setNodeRef(nodeRef);
// Maintain running list of "import" scoped ids
String importId = node.getImportId();
if (importId != null && importId.length() > 0)
{
createImportReference(parserContext, importId, nodeRef);
}
}
}
/**
* Maps an Import Id to a Node Reference
*
* @param importId import Id
* @param nodeRef node reference
*/
private void createImportReference(ParserContext parserContext, String importId, NodeRef nodeRef)
{
if (parserContext.importIds.containsKey(importId))
{
throw new ImporterException("Import id " + importId + " already specified within import file");
}
parserContext.importIds.put(importId, nodeRef);
}
/**
* Gets the Node Reference for the specified Import Id
*
* @param importId the import id
* @return the node reference
*/
private NodeRef getImportReference(ParserContext parserContext, String importId)
{
return parserContext.importIds.get(importId);
}
/**
* Get parent Node Context
*
@@ -715,14 +848,14 @@ public class ViewParser implements Parser
*/
private NodeContext peekNodeContext(Stack<ElementContext> contextStack)
{
ElementContext context = contextStack.peek();
if (context instanceof NodeContext)
ElementContext element = contextStack.peek();
if (element instanceof NodeContext)
{
return (NodeContext)context;
return (NodeContext)element;
}
else if (context instanceof NodeItemContext)
else if (element instanceof NodeItemContext)
{
return ((NodeItemContext)context).getNodeContext();
return ((NodeItemContext)element).getNodeContext();
}
throw new ImporterException("Internal error: Failed to retrieve node context");
}

View File

@@ -41,6 +41,16 @@ public interface ImporterProgress
*/
public void nodeCreated(NodeRef nodeRef, NodeRef parentRef, QName assocName, QName childName);
/**
* Report creation of a node link.
*
* @param nodeRef the node ref
* @param parentRef the parent ref
* @param assocName the child association type name
* @param childName the child association name
*/
public void nodeLinked(NodeRef nodeRef, NodeRef parentRef, QName assocName, QName childName);
/**
* Report creation of content
*

View File

@@ -286,6 +286,14 @@ public class Import extends Tool
logVerbose("Imported node " + nodeRef + " (parent=" + parentRef + ", childname=" + childName + ", association=" + assocName + ")");
}
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImporterProgress#nodeLinked(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName)
*/
public void nodeLinked(NodeRef nodeRef, NodeRef parentRef, QName assocName, QName childName)
{
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImporterProgress#contentCreated(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
*/