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(); public TypeDefinition getTypeDefinition();
/**
* @return is this a node reference
*/
public boolean isReference();
/** /**
* @return the node ref * @return the node ref
*/ */
@@ -55,7 +60,7 @@ public interface ImportNode
* @return node uuid to create node with * @return node uuid to create node with
*/ */
public String getUUID(); public String getUUID();
/** /**
* @return the child name * @return the child name
*/ */

View File

@@ -378,7 +378,7 @@ public class ImporterBootstrap
/** /**
* Bootstrap Binding * Bootstrap Binding
*/ */
private class BootstrapBinding implements ImporterBinding private static class BootstrapBinding implements ImporterBinding
{ {
private Properties configuration = null; private Properties configuration = null;
private ResourceBundle resourceBundle = 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 + ")"); 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) /* (non-Javadoc)
* @see org.alfresco.repo.importer.Progress#contentCreated(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) * @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 ImporterBinding binding;
private ImporterProgress progress; private ImporterProgress progress;
private ImportPackageHandler streamHandler; private ImportPackageHandler streamHandler;
private List<ImportedNodeRef> nodeRefs = new ArrayList<ImportedNodeRef>();
private NodeImporterStrategy importStrategy; private NodeImporterStrategy importStrategy;
private UpdateExistingNodeImporterStrategy updateStrategy;
// Import tracking
private List<ImportedNodeRef> nodeRefs = new ArrayList<ImportedNodeRef>();
// Flush threshold // Flush threshold
private int flushThreshold = 500; private int flushThreshold = 500;
@@ -392,6 +395,7 @@ public class ImporterComponent
this.progress = progress; this.progress = progress;
this.streamHandler = streamHandler; this.streamHandler = streamHandler;
this.importStrategy = createNodeImporterStrategy(binding == null ? null : binding.getUUIDBinding()); this.importStrategy = createNodeImporterStrategy(binding == null ? null : binding.getUUIDBinding());
this.updateStrategy = new UpdateExistingNodeImporterStrategy();
} }
/** /**
@@ -472,14 +476,22 @@ public class ImporterComponent
} }
} }
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see org.alfresco.repo.importer.Importer#importNode(org.alfresco.repo.importer.ImportNode) * @see org.alfresco.repo.importer.Importer#importNode(org.alfresco.repo.importer.ImportNode)
*/ */
public NodeRef importNode(ImportNode context) public NodeRef importNode(ImportNode context)
{ {
// import node // import node
NodeRef nodeRef = importStrategy.importNode(context); NodeRef nodeRef;
if (context.isReference())
{
nodeRef = linkNode(context);
}
else
{
nodeRef = importStrategy.importNode(context);
}
// apply aspects // apply aspects
for (QName aspect : context.getNodeAspects()) for (QName aspect : context.getNodeAspects())
@@ -511,6 +523,55 @@ public class ImporterComponent
return nodeRef; 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. * Import Node Content.
@@ -625,11 +686,7 @@ public class ImporterComponent
{ {
for (QName disabledBehaviour: disabledBehaviours) for (QName disabledBehaviour: disabledBehaviours)
{ {
boolean alreadyDisabled = behaviourFilter.disableBehaviour(importedRef.context.getNodeRef(), disabledBehaviour); behaviourFilter.disableBehaviour(importedRef.context.getNodeRef(), disabledBehaviour);
if (alreadyDisabled)
{
disabledBehaviours.remove(disabledBehaviour);
}
} }
nodeService.setProperty(importedRef.context.getNodeRef(), importedRef.property, nodeRef); nodeService.setProperty(importedRef.context.getNodeRef(), importedRef.property, nodeRef);
} }
@@ -648,6 +705,40 @@ public class ImporterComponent
{ {
behaviourFilter.enableAllBehaviours(); 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 * Get appropriate child association type for node to import under
@@ -830,7 +921,7 @@ public class ImporterComponent
} }
return objValue; return objValue;
} }
/** /**
* Helper to report node created progress * Helper to report node created progress
* *
@@ -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 * Helper to report content created progress
* *
@@ -938,30 +1043,12 @@ public class ImporterComponent
TypeDefinition nodeType = node.getTypeDefinition(); TypeDefinition nodeType = node.getTypeDefinition();
NodeRef parentRef = node.getParentContext().getParentRef(); NodeRef parentRef = node.getParentContext().getParentRef();
QName assocType = getAssocType(node); QName assocType = getAssocType(node);
QName childQName = null; QName childQName = getChildName(node);
if (childQName == null)
{
throw new ImporterException("Cannot determine child name of node (type: " + nodeType.getName() + ")");
}
// Determine child name
String childName = node.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 = 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);
}
// Create initial node (but, first disable behaviour for the node to be created) // Create initial node (but, first disable behaviour for the node to be created)
Set<QName> disabledBehaviours = getDisabledBehaviours(node); Set<QName> disabledBehaviours = getDisabledBehaviours(node);
for (QName disabledBehaviour: disabledBehaviours) for (QName disabledBehaviour: disabledBehaviours)
@@ -972,7 +1059,7 @@ public class ImporterComponent
disabledBehaviours.remove(disabledBehaviour); disabledBehaviours.remove(disabledBehaviour);
} }
} }
// Build initial map of properties // Build initial map of properties
Map<QName, Serializable> initialProperties = bindProperties(node); Map<QName, Serializable> initialProperties = bindProperties(node);
@@ -1154,8 +1241,11 @@ public class ImporterComponent
// do the update // do the update
Map<QName, Serializable> existingProperties = nodeService.getProperties(existingNodeRef); Map<QName, Serializable> existingProperties = nodeService.getProperties(existingNodeRef);
Map<QName, Serializable> updateProperties = bindProperties(node); Map<QName, Serializable> updateProperties = bindProperties(node);
existingProperties.putAll(updateProperties); if (updateProperties != null)
nodeService.setProperties(existingNodeRef, existingProperties); {
existingProperties.putAll(updateProperties);
nodeService.setProperties(existingNodeRef, existingProperties);
}
// Apply permissions // Apply permissions
boolean inheritPermissions = node.getInheritPermissions(); boolean inheritPermissions = node.getInheritPermissions();

View File

@@ -58,7 +58,6 @@ public class ImporterComponentTest extends BaseSpringTest
// Create the store // Create the store
this.storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis()); this.storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
} }
@Override @Override
protected void onTearDownInTransaction() throws Exception protected void onTearDownInTransaction() throws Exception
@@ -98,6 +97,12 @@ public class ImporterComponentTest extends BaseSpringTest
" (association " + assocName + ")"); " (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) public void contentCreated(NodeRef nodeRef, String sourceUrl)
{ {
System.out.println("TestProgress: created content " + nodeRef + " from url " + 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" <view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
xmlns:cm="http://www.alfresco.org/model/content/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:metadata>
<view:exportBy>unknown</view:exportBy> <view:exportBy>unknown</view:exportBy>
@@ -13,7 +13,7 @@
<view:exportOf>/system</view:exportOf> <view:exportOf>/system</view:exportOf>
</view:metadata> </view:metadata>
<cm:systemfolder view:childName="system"> <cm:systemfolder view:childName="system" view:id="the root system folder">
<cm:name>System</cm:name> <cm:name>System</cm:name>
<cm:orderedchildren>true</cm:orderedchildren> <cm:orderedchildren>true</cm:orderedchildren>
<cm:contains> <cm:contains>
@@ -32,43 +32,58 @@
</view:properties> </view:properties>
<view:associations> <view:associations>
<cm:contains> <cm:contains>
<cm:person view:childName="cm:fredb"> <cm:person view:childName="cm:fredb" view:id="fred">
<view:aspects/> <view:aspects/>
<view:properties> <view:properties>
<cm:userName>${username}</cm:userName> <cm:userName>${username}</cm:userName>
<cm:firstName>Fred</cm:firstName> <cm:firstName>Fred</cm:firstName>
<cm:lastName>Bloggs</cm:lastName> <cm:lastName>Bloggs</cm:lastName>
<cm:homeFolder>../../cm:people_x0020_folder</cm:homeFolder> <cm:homeFolder>../../cm:people_x0020_folder</cm:homeFolder>
</view:properties> </view:properties>
</cm:person> </cm:person>
</cm:contains> </cm:contains>
</view:associations> </view:associations>
</cm:systemfolder> </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 --> <!-- note: if no explicit view:childName, take from name if one exists -->
<cm:cmobject> <cm:cmobject>
<cm:translatable/> <cm:translatable/>
<cm:generalclassifiable/> <cm:generalclassifiable/>
<cm:name>Some Content</cm:name> <cm:name>Categorised Content</cm:name>
<cm:categories> <cm:categories>
<view:value>../cm:people_x0020_folder</view:value> <view:value>../cm:people_x0020_folder</view:value>
<view:value>../cm:people_x0020_folder</view:value> <view:value>../cm:people_x0020_folder</view:value>
</cm:categories> </cm:categories>
<cm:translations view:idref="xyz"/>
</cm:cmobject> </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:contains>
</cm:systemfolder> </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:view>

View File

@@ -51,15 +51,17 @@ public class NodeContext extends ElementContext
implements ImportNode implements ImportNode
{ {
private ParentContext parentContext; private ParentContext parentContext;
private boolean isReference = false;
private NodeRef nodeRef; 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 TypeDefinition typeDef;
private String childName; private String childName;
private Map<QName, AspectDefinition> nodeAspects = new HashMap<QName, AspectDefinition>(); private Map<QName, AspectDefinition> nodeAspects = new HashMap<QName, AspectDefinition>();
private Map<QName, ChildAssociationDefinition> nodeChildAssocs = new HashMap<QName, ChildAssociationDefinition>(); private Map<QName, ChildAssociationDefinition> nodeChildAssocs = new HashMap<QName, ChildAssociationDefinition>();
private Map<QName, Serializable> nodeProperties = new HashMap<QName, Serializable>(); private Map<QName, Serializable> nodeProperties = new HashMap<QName, Serializable>();
private Map<QName, DataTypeDefinition> propertyDatatypes = new HashMap<QName, DataTypeDefinition>(); private Map<QName, DataTypeDefinition> propertyDatatypes = new HashMap<QName, DataTypeDefinition>();
// permissions // permissions
private boolean inherit = true; private boolean inherit = true;
private List<AccessPermission> accessControlEntries = new ArrayList<AccessPermission>(); private List<AccessPermission> accessControlEntries = new ArrayList<AccessPermission>();
@@ -79,7 +81,7 @@ public class NodeContext extends ElementContext
this.typeDef = typeDef; this.typeDef = typeDef;
this.uuid = null; this.uuid = null;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#getParentContext() * @see org.alfresco.repo.importer.ImportNode#getParentContext()
*/ */
@@ -96,6 +98,23 @@ public class NodeContext extends ElementContext
return typeDef; 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 * Set Type Definition
* *
@@ -139,6 +158,23 @@ public class NodeContext extends ElementContext
this.uuid = uuid; 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) /* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#getChildName() * @see org.alfresco.repo.importer.ImportNode#getChildName()
*/ */
@@ -369,11 +405,14 @@ public class NodeContext extends ElementContext
PropertyDefinition def = null; PropertyDefinition def = null;
if (nodeProperties.containsKey(defName) == false) if (nodeProperties.containsKey(defName) == false)
{ {
def = getDictionaryService().getProperty(typeDef.getName(), defName); def = (typeDef == null) ? null : getDictionaryService().getProperty(typeDef.getName(), defName);
if (def == null) if (def == null)
{ {
Set<AspectDefinition> allAspects = new HashSet<AspectDefinition>(); Set<AspectDefinition> allAspects = new HashSet<AspectDefinition>();
allAspects.addAll(typeDef.getDefaultAspects()); if (typeDef != null)
{
allAspects.addAll(typeDef.getDefaultAspects());
}
allAspects.addAll(nodeAspects.values()); allAspects.addAll(nodeAspects.values());
for (AspectDefinition aspectDef : allAspects) for (AspectDefinition aspectDef : allAspects)
{ {

View File

@@ -84,18 +84,22 @@ public class ParentContext extends ElementContext
{ {
this(elementName, parent); this(elementName, parent);
// Ensure association is valid for node TypeDefinition typeDef = parent.getTypeDefinition();
Set<QName> allAspects = new HashSet<QName>(); if (typeDef != null)
for (AspectDefinition typeAspect : parent.getTypeDefinition().getDefaultAspects())
{ {
allAspects.add(typeAspect.getName()); // Ensure association type is valid for node parent
} Set<QName> allAspects = new HashSet<QName>();
allAspects.addAll(parent.getNodeAspects()); for (AspectDefinition typeAspect : parent.getTypeDefinition().getDefaultAspects())
TypeDefinition anonymousType = getDictionaryService().getAnonymousType(parent.getTypeDefinition().getName(), allAspects); {
Map<QName, ChildAssociationDefinition> nodeAssociations = anonymousType.getChildAssociations(); allAspects.add(typeAspect.getName());
if (nodeAssociations.containsKey(childDef.getName()) == false) }
{ allAspects.addAll(parent.getNodeAspects());
throw new ImporterException("Association " + childDef.getName() + " is not valid for node " + parent.getTypeDefinition().getName()); TypeDefinition anonymousType = getDictionaryService().getAnonymousType(parent.getTypeDefinition().getName(), allAspects);
Map<QName, ChildAssociationDefinition> nodeAssociations = anonymousType.getChildAssociations();
if (nodeAssociations.containsKey(childDef.getName()) == false)
{
throw new ImporterException("Association " + childDef.getName() + " is not valid for node " + parent.getTypeDefinition().getName());
}
} }
parentRef = parent.getNodeRef(); parentRef = parent.getNodeRef();

View File

@@ -18,18 +18,21 @@ package org.alfresco.repo.importer.view;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack; import java.util.Stack;
import org.alfresco.repo.importer.Importer; import org.alfresco.repo.importer.Importer;
import org.alfresco.repo.importer.Parser; import org.alfresco.repo.importer.Parser;
import org.alfresco.service.cmr.dictionary.AspectDefinition; 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.ChildAssociationDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition; import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef; 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.security.AccessStatus;
import org.alfresco.service.cmr.view.ImporterException;
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.apache.commons.logging.Log; 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_ISNULL_ATTR = "isNull";
private static final String VIEW_INHERIT_PERMISSIONS_ATTR = "inherit"; private static final String VIEW_INHERIT_PERMISSIONS_ATTR = "inherit";
private static final String VIEW_ACCESS_STATUS_ATTR = "access"; 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_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_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"); 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_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_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_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 // XML Pull Parser Factory
@@ -73,8 +79,17 @@ public class ViewParser implements Parser
// Supporting services // Supporting services
private NamespaceService namespaceService; private NamespaceService namespaceService;
private DictionaryService dictionaryService; 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 * Construct
*/ */
@@ -92,6 +107,7 @@ public class ViewParser implements Parser
} }
} }
/** /**
* @param namespaceService the namespace service * @param namespaceService the namespace service
*/ */
@@ -117,7 +133,11 @@ public class ViewParser implements Parser
{ {
XmlPullParser xpp = factory.newPullParser(); XmlPullParser xpp = factory.newPullParser();
xpp.setInput(viewReader); 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 try
{ {
@@ -129,17 +149,17 @@ public class ViewParser implements Parser
{ {
if (xpp.getDepth() == 1) if (xpp.getDepth() == 1)
{ {
processRoot(xpp, importer, contextStack); processRoot(xpp, parserContext);
} }
else else
{ {
processStartElement(xpp, contextStack); processStartElement(xpp, parserContext);
} }
break; break;
} }
case XmlPullParser.END_TAG: case XmlPullParser.END_TAG:
{ {
processEndElement(xpp, contextStack); processEndElement(xpp, parserContext);
break; break;
} }
} }
@@ -164,61 +184,69 @@ public class ViewParser implements Parser
* @throws XmlPullParserException * @throws XmlPullParserException
* @throws IOException * @throws IOException
*/ */
private void processStartElement(XmlPullParser xpp, Stack<ElementContext> contextStack) private void processStartElement(XmlPullParser xpp, ParserContext parserContext)
throws XmlPullParserException, IOException throws XmlPullParserException, IOException
{ {
// Extract qualified name // Extract qualified name
QName defName = getName(xpp); QName defName = getName(xpp);
// Process the element // Process the element
Object context = contextStack.peek(); Object element = parserContext.elementStack.peek();
// Handle special view directives // Handle special view directives
if (defName.equals(VIEW_METADATA)) 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)) 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"); throw new ImporterException("Element " + defName + " can only be declared within a node");
} }
NodeContext nodeContext = (NodeContext)context; NodeContext node = (NodeContext)element;
contextStack.push(new NodeItemContext(defName, nodeContext)); parserContext.elementStack.push(new NodeItemContext(defName, node));
// process ACL specific attributes // process ACL specific attributes
if (defName.equals(VIEW_ACL)) if (defName.equals(VIEW_ACL))
{ {
processACL(xpp, contextStack); processACL(xpp, parserContext);
} }
} }
else 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)
{ {
// Process type definition if (defName.equals(VIEW_REFERENCE))
TypeDefinition typeDef = dictionaryService.getType(defName);
if (typeDef == null)
{ {
throw new ImporterException("Type " + defName + " has not been defined in the Repository dictionary"); // Process reference
processStartReference(xpp, defName, parserContext);
}
else
{
// Process type definition
TypeDefinition typeDef = dictionaryService.getType(defName);
if (typeDef == null)
{
throw new ImporterException("Type " + defName + " has not been defined in the Repository dictionary");
}
processStartType(xpp, typeDef, parserContext);
} }
processStartType(xpp, typeDef, contextStack);
return; return;
} }
else if (context instanceof NodeContext) else if (element instanceof NodeContext)
{ {
// Process children of node // Process children of node
// Note: Process in the following order: aspects, properties and associations // 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) if (def == null)
{ {
throw new ImporterException("Definition " + defName + " is not valid; cannot find in Repository dictionary"); 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) if (def instanceof AspectDefinition)
{ {
processAspect(xpp, (AspectDefinition)def, contextStack); processAspect(xpp, (AspectDefinition)def, parserContext);
return; return;
} }
else if (def instanceof PropertyDefinition) else if (def instanceof PropertyDefinition)
{ {
processProperty(xpp, ((PropertyDefinition)def).getName(), contextStack); processProperty(xpp, ((PropertyDefinition)def).getName(), parserContext);
return; return;
} }
else if (def instanceof ChildAssociationDefinition) else if (def instanceof ChildAssociationDefinition)
{ {
processStartChildAssoc(xpp, (ChildAssociationDefinition)def, contextStack); processStartChildAssoc(xpp, (ChildAssociationDefinition)def, parserContext);
return; return;
} }
else else
@@ -244,38 +272,42 @@ public class ViewParser implements Parser
// TODO: general association // TODO: general association
} }
} }
else if (context instanceof NodeItemContext) else if (element instanceof NodeItemContext)
{ {
NodeItemContext nodeItemContext = (NodeItemContext)context; NodeItemContext nodeItem = (NodeItemContext)element;
NodeContext nodeContext = nodeItemContext.getNodeContext(); NodeContext node = nodeItem.getNodeContext();
QName itemName = nodeItemContext.getElementName(); QName itemName = nodeItem.getElementName();
if (itemName.equals(VIEW_ASPECTS)) if (itemName.equals(VIEW_ASPECTS))
{ {
AspectDefinition def = nodeContext.determineAspect(defName); AspectDefinition def = node.determineAspect(defName);
if (def == null) if (def == null)
{ {
throw new ImporterException("Aspect name " + defName + " is not valid; cannot find in Repository dictionary"); 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)) else if (itemName.equals(VIEW_PROPERTIES))
{ {
// Note: Allow properties which do not have a data dictionary definition // 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)) else if (itemName.equals(VIEW_ASSOCIATIONS))
{ {
// TODO: Handle general associations... AssociationDefinition def = (AssociationDefinition)node.determineAssociation(defName);
ChildAssociationDefinition def = (ChildAssociationDefinition)nodeContext.determineAssociation(defName);
if (def == null) if (def == null)
{ {
throw new ImporterException("Association name " + defName + " is not valid; cannot find in Repository dictionary"); 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)) else if (itemName.equals(VIEW_ACL))
{ {
processAccessControlEntry(xpp, contextStack); processAccessControlEntry(xpp, parserContext);
} }
} }
} }
@@ -293,14 +325,14 @@ public class ViewParser implements Parser
* @throws XmlPullParserException * @throws XmlPullParserException
* @throws IOException * @throws IOException
*/ */
private void processRoot(XmlPullParser xpp, Importer importer, Stack<ElementContext> contextStack) private void processRoot(XmlPullParser xpp, ParserContext parserContext)
throws XmlPullParserException, IOException throws XmlPullParserException, IOException
{ {
ParentContext parentContext = new ParentContext(getName(xpp), dictionaryService, importer); ParentContext parent = new ParentContext(getName(xpp), parserContext.dictionaryService, parserContext.importer);
contextStack.push(parentContext); parserContext.elementStack.push(parent);
if (logger.isDebugEnabled()) 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 XmlPullParserException
* @throws IOException * @throws IOException
*/ */
private void processMetaData(XmlPullParser xpp, QName metaDataName, Stack<ElementContext> contextStack) private void processMetaData(XmlPullParser xpp, QName metaDataName, ParserContext parserContext)
throws XmlPullParserException, IOException throws XmlPullParserException, IOException
{ {
MetaDataContext context = (MetaDataContext)contextStack.peek(); MetaDataContext metaData = (MetaDataContext)parserContext.elementStack.peek();
String value = null; String value = null;
@@ -331,7 +363,7 @@ public class ViewParser implements Parser
throw new ImporterException("Meta data element " + metaDataName + " is missing end tag"); throw new ImporterException("Meta data element " + metaDataName + " is missing end tag");
} }
context.setProperty(metaDataName, value); metaData.setProperty(metaDataName, value);
} }
/** /**
@@ -343,25 +375,88 @@ public class ViewParser implements Parser
* @throws XmlPullParserException * @throws XmlPullParserException
* @throws IOException * @throws IOException
*/ */
private void processStartType(XmlPullParser xpp, TypeDefinition typeDef, Stack<ElementContext> contextStack) private void processStartType(XmlPullParser xpp, TypeDefinition typeDef, ParserContext parserContext)
throws XmlPullParserException, IOException throws XmlPullParserException, IOException
{ {
ParentContext parentContext = (ParentContext)contextStack.peek(); ParentContext parent = (ParentContext)parserContext.elementStack.peek();
NodeContext context = new NodeContext(typeDef.getName(), parentContext, typeDef); 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)
{
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 " + 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 // Extract child name if explicitly defined
String childName = xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_CHILD_NAME_ATTR); String childName = xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_CHILD_NAME_ATTR);
if (childName != null && childName.length() > 0) 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()) if (logger.isDebugEnabled())
logger.debug(indentLog("Pushed " + context, contextStack.size() -1)); logger.debug(indentLog("Pushed Reference " + node, parserContext.elementStack.size() -1));
} }
/** /**
* Process aspect definition * Process aspect definition
* *
@@ -371,11 +466,11 @@ public class ViewParser implements Parser
* @throws XmlPullParserException * @throws XmlPullParserException
* @throws IOException * @throws IOException
*/ */
private void processAspect(XmlPullParser xpp, AspectDefinition aspectDef, Stack<ElementContext> contextStack) private void processAspect(XmlPullParser xpp, AspectDefinition aspectDef, ParserContext parserContext)
throws XmlPullParserException, IOException throws XmlPullParserException, IOException
{ {
NodeContext context = peekNodeContext(contextStack); NodeContext node = peekNodeContext(parserContext.elementStack);
context.addAspect(aspectDef); node.addAspect(aspectDef);
int eventType = xpp.next(); int eventType = xpp.next();
if (eventType != XmlPullParser.END_TAG) if (eventType != XmlPullParser.END_TAG)
@@ -384,7 +479,7 @@ public class ViewParser implements Parser
} }
if (logger.isDebugEnabled()) 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 xpp
* @param contextStack * @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); String strInherit = xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_INHERIT_PERMISSIONS_ATTR);
if (strInherit != null) if (strInherit != null)
@@ -403,7 +498,7 @@ public class ViewParser implements Parser
Boolean inherit = Boolean.valueOf(strInherit); Boolean inherit = Boolean.valueOf(strInherit);
if (!inherit) if (!inherit)
{ {
context.setInheritPermissions(false); node.setInheritPermissions(false);
} }
} }
} }
@@ -416,10 +511,10 @@ public class ViewParser implements Parser
* @throws XmlPullParserException * @throws XmlPullParserException
* @throws IOException * @throws IOException
*/ */
private void processAccessControlEntry(XmlPullParser xpp, Stack<ElementContext> contextStack) private void processAccessControlEntry(XmlPullParser xpp, ParserContext parserContext)
throws XmlPullParserException, IOException throws XmlPullParserException, IOException
{ {
NodeContext context = peekNodeContext(contextStack); NodeContext node = peekNodeContext(parserContext.elementStack);
QName defName = getName(xpp); QName defName = getName(xpp);
if (!defName.equals(VIEW_ACE)) if (!defName.equals(VIEW_ACE))
@@ -500,7 +595,7 @@ public class ViewParser implements Parser
} }
// update node context // 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 XmlPullParserException
* @throws IOException * @throws IOException
*/ */
private void processProperty(XmlPullParser xpp, QName propertyName, Stack<ElementContext> contextStack) private void processProperty(XmlPullParser xpp, QName propertyName, ParserContext parserContext)
throws XmlPullParserException, IOException throws XmlPullParserException, IOException
{ {
NodeContext context = peekNodeContext(contextStack); NodeContext node = peekNodeContext(parserContext.elementStack);
// Extract single value // Extract single value
String value = ""; String value = "";
@@ -527,11 +622,10 @@ public class ViewParser implements Parser
} }
if (eventType == XmlPullParser.END_TAG) if (eventType == XmlPullParser.END_TAG)
{ {
context.addProperty(propertyName, value); node.addProperty(propertyName, value);
} }
else else
{ {
// Extract collection, if specified // Extract collection, if specified
boolean isCollection = false; boolean isCollection = false;
if (eventType == XmlPullParser.START_TAG) if (eventType == XmlPullParser.START_TAG)
@@ -539,7 +633,7 @@ public class ViewParser implements Parser
QName name = getName(xpp); QName name = getName(xpp);
if (name.equals(VIEW_VALUES_QNAME)) if (name.equals(VIEW_VALUES_QNAME))
{ {
context.addPropertyCollection(propertyName); node.addPropertyCollection(propertyName);
isCollection = true; isCollection = true;
eventType = xpp.next(); eventType = xpp.next();
if (eventType == XmlPullParser.TEXT) if (eventType == XmlPullParser.TEXT)
@@ -568,10 +662,10 @@ public class ViewParser implements Parser
} }
if (eventType == XmlPullParser.END_TAG) if (eventType == XmlPullParser.END_TAG)
{ {
context.addProperty(propertyName, decoratedValue); node.addProperty(propertyName, decoratedValue);
if (datatype != null) if (datatype != null)
{ {
context.addDatatype(propertyName, dictionaryService.getDataType(datatype)); node.addDatatype(propertyName, dictionaryService.getDataType(datatype));
} }
} }
else else
@@ -604,11 +698,10 @@ public class ViewParser implements Parser
throw new ImporterException("Invalid view structure - property " + propertyName + " definition is invalid"); throw new ImporterException("Invalid view structure - property " + propertyName + " definition is invalid");
} }
} }
} }
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug(indentLog("Processed property " + propertyName, contextStack.size())); logger.debug(indentLog("Processed property " + propertyName, parserContext.elementStack.size()));
} }
/** /**
@@ -620,54 +713,48 @@ public class ViewParser implements Parser
* @throws XmlPullParserException * @throws XmlPullParserException
* @throws IOException * @throws IOException
*/ */
private void processStartChildAssoc(XmlPullParser xpp, ChildAssociationDefinition childAssocDef, Stack<ElementContext> contextStack) private void processStartChildAssoc(XmlPullParser xpp, ChildAssociationDefinition childAssocDef, ParserContext parserContext)
throws XmlPullParserException, IOException throws XmlPullParserException, IOException
{ {
NodeContext context = peekNodeContext(contextStack); NodeContext node = peekNodeContext(parserContext.elementStack);
importNode(parserContext, node);
if (context.getNodeRef() == null)
{
// Create Node
NodeRef nodeRef = context.getImporter().importNode(context);
context.setNodeRef(nodeRef);
}
// Construct Child Association Context // Construct Child Association Context
ParentContext parentContext = new ParentContext(childAssocDef.getName(), context, childAssocDef); ParentContext parent = new ParentContext(childAssocDef.getName(), node, childAssocDef);
contextStack.push(parentContext); parserContext.elementStack.push(parent);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug(indentLog("Pushed " + parentContext, contextStack.size() -1)); logger.debug(indentLog("Pushed " + parent, parserContext.elementStack.size() -1));
} }
/** /**
* Process end of xml element * Process end of xml element
* *
* @param xpp * @param xpp
* @param contextStack * @param contextStack
*/ */
private void processEndElement(XmlPullParser xpp, Stack<ElementContext> contextStack) private void processEndElement(XmlPullParser xpp, ParserContext parserContext)
{ {
ElementContext context = contextStack.peek(); ElementContext element = parserContext.elementStack.peek();
if (context.getElementName().getLocalName().equals(xpp.getName()) && if (element.getElementName().getLocalName().equals(xpp.getName()) &&
context.getElementName().getNamespaceURI().equals(xpp.getNamespace())) element.getElementName().getNamespaceURI().equals(xpp.getNamespace()))
{ {
context = contextStack.pop(); element = parserContext.elementStack.pop();
if (logger.isDebugEnabled()) 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 * 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(); NodeRef nodeRef = node.getNodeRef();
if (nodeRef == null) importNode(parserContext, node);
{ node.getImporter().childrenImported(nodeRef);
nodeRef = context.getImporter().importNode(context);
context.setNodeRef(nodeRef);
}
context.getImporter().childrenImported(nodeRef);
} }
/** /**
@@ -693,7 +776,7 @@ public class ViewParser implements Parser
* *
* @param context * @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 * @param context
*/ */
private void processEndMetaData(MetaDataContext context) private void processEndMetaData(ParserContext parserContext, MetaDataContext context)
{ {
context.getImporter().importMetaData(context.getProperties()); 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 * Get parent Node Context
* *
@@ -715,14 +848,14 @@ public class ViewParser implements Parser
*/ */
private NodeContext peekNodeContext(Stack<ElementContext> contextStack) private NodeContext peekNodeContext(Stack<ElementContext> contextStack)
{ {
ElementContext context = contextStack.peek(); ElementContext element = contextStack.peek();
if (context instanceof NodeContext) 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"); 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); 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 * 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 + ")"); 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) /* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImporterProgress#contentCreated(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) * @see org.alfresco.service.cmr.view.ImporterProgress#contentCreated(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
*/ */