Files
.externalToolBuilders
config
source
cpp
java
org
alfresco
email
filesys
jcr
api
dictionary
exporter
importer
ImportTest.java
JCRDocXMLHandler.java
JCRImportHandler.java
JCRSystemXMLHandler.java
PropertyContext.java
ValueContext.java
item
query
repository
session
tck
test
util
version
linkvalidation
model
repo
sandbox
service
tools
util
apache
queryRegister.dtd
meta-inf
test-resources
web
.classpath
.project
build.xml
alfresco-community-repo/source/java/org/alfresco/jcr/importer/JCRSystemXMLHandler.java
Paul Holmes-Higgin 4e2300f095 Updated copyright
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5186 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2007-02-19 17:17:36 +00:00

561 lines
19 KiB
Java

/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.jcr.importer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.List;
import java.util.Stack;
import javax.jcr.InvalidSerializedDataException;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import org.alfresco.jcr.dictionary.DataTypeMap;
import org.alfresco.jcr.dictionary.JCRNamespace;
import org.alfresco.jcr.exporter.JCRSystemXMLExporter;
import org.alfresco.jcr.item.property.JCRMixinTypesProperty;
import org.alfresco.jcr.item.property.JCRPrimaryTypeProperty;
import org.alfresco.jcr.item.property.JCRUUIDProperty;
import org.alfresco.jcr.session.SessionImpl;
import org.alfresco.repo.importer.ImportContentHandler;
import org.alfresco.repo.importer.Importer;
import org.alfresco.repo.importer.view.ElementContext;
import org.alfresco.repo.importer.view.NodeContext;
import org.alfresco.repo.importer.view.ParentContext;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.view.ImporterException;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Base64;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* Alfresco implementation of a System View Import Content Handler
*
* @author David Caruana
*/
public class JCRSystemXMLHandler implements ImportContentHandler
{
private Importer importer;
private SessionImpl session;
private NamespacePrefixResolver importResolver;
private Stack<ElementContext> contextStack = new Stack<ElementContext>();
/**
* Construct
*
* @param session JCR Session
* @param importResolver Namespace Resolver for the Import
*/
public JCRSystemXMLHandler(SessionImpl session, NamespacePrefixResolver importResolver)
{
this.session = session;
this.importResolver = importResolver;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportContentHandler#setImporter(org.alfresco.repo.importer.Importer)
*/
public void setImporter(Importer importer)
{
this.importer = importer;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportContentHandler#importStream(java.lang.String)
*/
public InputStream importStream(String content)
{
File contentFile = new File(content);
try
{
FileInputStream contentStream = new FileInputStream(contentFile);
return new Base64.InputStream(contentStream, Base64.DECODE | Base64.DONT_BREAK_LINES);
}
catch (FileNotFoundException e)
{
throw new ImporterException("Failed to retrieve import input stream on temporary content file " + content);
}
}
/*
* (non-Javadoc)
* @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
*/
public void setDocumentLocator(Locator locator)
{
// NOOP
}
/*
* (non-Javadoc)
* @see org.xml.sax.ContentHandler#startDocument()
*/
public void startDocument() throws SAXException
{
// NOOP
}
/*
* (non-Javadoc)
* @see org.xml.sax.ContentHandler#endDocument()
*/
public void endDocument() throws SAXException
{
// NOOP
}
/*
* (non-Javadoc)
* @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
*/
public void startPrefixMapping(String prefix, String uri) throws SAXException
{
// NOOP
}
/*
* (non-Javadoc)
* @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
*/
public void endPrefixMapping(String prefix) throws SAXException
{
// NOOP
}
/*
* (non-Javadoc)
* @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException
{
try
{
// construct qname for element
QName elementName = QName.createQName(qName, importResolver);
if (JCRSystemXMLExporter.NODE_QNAME.equals(elementName))
{
processStartNode(elementName, atts);
}
else if (JCRSystemXMLExporter.PROPERTY_QNAME.equals(elementName))
{
processStartProperty(elementName, atts);
}
else if (JCRSystemXMLExporter.VALUE_QNAME.equals(elementName))
{
processStartValue(elementName, atts);
}
}
catch(Exception e)
{
throw new SAXException("Failed to process element " + qName, e);
}
}
/**
* Process start of Node Element
*
* @param elementName
* @param atts
* @throws InvalidSerializedDataException
*/
private void processStartNode(QName elementName, Attributes atts)
throws InvalidSerializedDataException
{
ParentContext parentContext = null;
if (contextStack.empty())
{
// create root parent context
parentContext = new ParentContext(elementName, session.getRepositoryImpl().getServiceRegistry().getDictionaryService(), importer);
}
else
{
NodeContext parentNode = (NodeContext)contextStack.peek();
// if we haven't yet imported the node before its children, do so now
if (parentNode.getNodeRef() == null)
{
NodeRef nodeRef = importer.importNode(parentNode);
parentNode.setNodeRef(nodeRef);
}
// create parent context
parentContext = new ParentContext(elementName, parentNode);
}
// create node context
// NOTE: we don't yet know its type (we have to wait for a property)
NodeContext nodeContext = new NodeContext(elementName, parentContext, null);
// establish node child name
String name = atts.getValue(JCRSystemXMLExporter.NAME_QNAME.toPrefixString(importResolver));
if (name == null)
{
throw new InvalidSerializedDataException("Mandatory sv:name attribute of element sv:node not present.");
}
nodeContext.setChildName(name);
// record new node
contextStack.push(nodeContext);
}
/**
* Process start of Property element
*
* @param elementName
* @param atts
* @throws InvalidSerializedDataException
*/
private void processStartProperty(QName elementName, Attributes atts)
throws InvalidSerializedDataException
{
// establish correct context
ElementContext context = contextStack.peek();
if (!(context instanceof NodeContext))
{
throw new InvalidSerializedDataException("Element " + elementName + " not expected.");
}
NodeContext parentNode = (NodeContext)context;
// establish property name
String name = atts.getValue(JCRSystemXMLExporter.NAME_QNAME.toPrefixString(importResolver));
if (name == null)
{
throw new InvalidSerializedDataException("Mandatory sv:name attribute of element sv:node not present.");
}
QName propertyName = QName.createQName(name, importResolver);
// establish property type and validate property type
QName dataType = null;
String type = atts.getValue(JCRSystemXMLExporter.TYPE_QNAME.toPrefixString(importResolver));
if (type == null)
{
throw new InvalidSerializedDataException("Mandatory sv:type attribute of element sv:node not present.");
}
try
{
dataType = DataTypeMap.convertPropertyTypeToDataType(PropertyType.valueFromName(type));
}
catch(IllegalArgumentException e)
{
throw new ImporterException("Type " + type + " is not known for property " + name);
}
// construct property context
PropertyContext propertyContext = new PropertyContext(elementName, parentNode, propertyName, dataType);
contextStack.push(propertyContext);
}
/**
* Process start of Value element
*
* @param elementName
* @param atts
* @throws InvalidSerializedDataException
*/
private void processStartValue(QName elementName, Attributes atts)
throws InvalidSerializedDataException
{
// establish correct context
ElementContext context = contextStack.peek();
if (!(context instanceof PropertyContext))
{
throw new InvalidSerializedDataException("Element " + elementName + " not expected.");
}
PropertyContext property = (PropertyContext)context;
property.startValue();
ValueContext value = new ValueContext(elementName, property);
contextStack.push(value);
}
/*
* (non-Javadoc)
* @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
public void endElement(String uri, String localName, String qName) throws SAXException
{
try
{
// ensure context matches parse
ElementContext context = (ElementContext)contextStack.peek();
QName elementName = QName.createQName(qName, importResolver);
if (!context.getElementName().equals(elementName))
{
throw new InvalidSerializedDataException("Expected element " + context.getElementName() + " but was " + elementName);
}
if (JCRSystemXMLExporter.NODE_QNAME.equals(elementName))
{
processEndNode((NodeContext)context);
}
else if (JCRSystemXMLExporter.PROPERTY_QNAME.equals(elementName))
{
processEndProperty((PropertyContext)context);
}
else if (JCRSystemXMLExporter.VALUE_QNAME.equals(elementName))
{
processEndValue((ValueContext)context);
}
// cleanup
contextStack.pop();
}
catch(Exception e)
{
throw new SAXException("Failed to process element " + qName, e);
}
}
/**
* Process end of Node element
*
* @param node
*/
private void processEndNode(NodeContext node)
{
// import node, if not already imported (this will be the case when no child nodes exist)
NodeRef nodeRef = node.getNodeRef();
if (nodeRef == null)
{
nodeRef = node.getImporter().importNode(node);
node.setNodeRef(nodeRef);
}
// signal end of node
node.getImporter().childrenImported(nodeRef);
}
/**
* Process end of Property element
*
* @param context
* @throws InvalidSerializedDataException
* @throws RepositoryException
*/
private void processEndProperty(PropertyContext context)
throws InvalidSerializedDataException, RepositoryException
{
QName propertyName = context.getName();
// ensure a value has been provided
if (context.isNull())
{
throw new InvalidSerializedDataException("Property " + propertyName + " must have a value");
}
//
// process known properties
//
if (JCRPrimaryTypeProperty.PROPERTY_NAME.equals(propertyName))
{
// apply type definition
if (!context.isNull())
{
QName typeQName = QName.createQName(context.getValues().get(0).toString(), importResolver);
TypeDefinition typeDef = context.getDictionaryService().getType(typeQName);
if (typeDef == null)
{
throw new InvalidTypeException(typeQName);
}
// update node context
context.getNode().setTypeDefinition(typeDef);
}
}
else if (JCRMixinTypesProperty.PROPERTY_NAME.equals(propertyName))
{
// apply aspect definitions
List<StringBuffer> values = context.getValues();
for (StringBuffer value : values)
{
QName aspectQName = QName.createQName(value.toString(), importResolver);
// ignore JCR specific aspects
if (!(JCRNamespace.JCR_URI.equals(aspectQName.getNamespaceURI()) ||
JCRNamespace.MIX_URI.equals(aspectQName.getNamespaceURI())))
{
AspectDefinition aspectDef = context.getDictionaryService().getAspect(aspectQName);
if (aspectDef == null)
{
throw new InvalidTypeException(aspectQName);
}
context.getNode().addAspect(aspectDef);
}
}
}
else if (JCRUUIDProperty.PROPERTY_NAME.equals(propertyName))
{
StringBuffer value = context.getValues().get(0);
context.getNode().setUUID(value.toString());
}
//
// Note: ignore all other JCR specific properties
//
else if (JCRNamespace.JCR_URI.equals(propertyName.getNamespaceURI()))
{
}
//
// process all other properties
//
else
{
// apply the property values to the node
NodeContext node = context.getNode();
if (node.getTypeDefinition() == null)
{
throw new InvalidSerializedDataException("Node jcr:primaryType property has not been specified.");
}
// determine data type of value
QName dataType = context.getType();
DataTypeDefinition dataTypeDef = context.getDictionaryService().getDataType(dataType);
if (dataTypeDef == null)
{
throw new InvalidTypeException(dataType);
}
node.addDatatype(propertyName, dataTypeDef);
// determine if multi-value property
if (context.isMultiValue())
{
node.addPropertyCollection(propertyName);
}
// add each value to the node
List<StringBuffer> values = context.getValues();
for (StringBuffer value : values)
{
// first, cast value to appropriate type (using JCR converters)
Serializable objVal = (Serializable)session.getTypeConverter().convert(dataTypeDef, value.toString());
String strValue = DefaultTypeConverter.INSTANCE.convert(String.class, objVal);
node.addProperty(propertyName, strValue);
}
}
}
/**
* Process end of value element
*
* @param context
*/
private void processEndValue(ValueContext context)
{
PropertyContext property = context.getProperty();
property.endValue();
}
/*
* (non-Javadoc)
* @see org.xml.sax.ContentHandler#characters(char[], int, int)
*/
public void characters(char[] ch, int start, int length) throws SAXException
{
ElementContext context = (ElementContext)contextStack.peek();
if (context instanceof ValueContext)
{
PropertyContext property = ((ValueContext)context).getProperty();
property.appendCharacters(ch, start, length);
}
}
/*
* (non-Javadoc)
* @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
*/
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
{
ElementContext context = (ElementContext)contextStack.peek();
if (context instanceof ValueContext)
{
PropertyContext property = ((ValueContext)context).getProperty();
property.appendCharacters(ch, start, length);
}
}
/*
* (non-Javadoc)
* @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
*/
public void processingInstruction(String target, String data) throws SAXException
{
}
/*
* (non-Javadoc)
* @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
*/
public void skippedEntity(String name) throws SAXException
{
}
/*
* (non-Javadoc)
* @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
*/
public void warning(SAXParseException exception) throws SAXException
{
}
/*
* (non-Javadoc)
* @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
*/
public void error(SAXParseException exception) throws SAXException
{
}
/*
* (non-Javadoc)
* @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
*/
public void fatalError(SAXParseException exception) throws SAXException
{
}
}