Moving to root below branch label

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2005 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2005-12-08 07:13:07 +00:00
commit e1e6508fec
1095 changed files with 230566 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.alfresco.service.cmr.view.ImportPackageHandler;
import org.alfresco.service.cmr.view.ImporterException;
/**
* Handler for importing Repository content from zip package file
*
* @author David Caruana
*/
public class ACPImportPackageHandler
implements ImportPackageHandler
{
protected File file;
protected ZipFile zipFile;
protected String dataFileEncoding;
/**
* Constuct Handler
*
* @param sourceDir source directory
* @param packageDir relative directory within source to place exported content
*/
public ACPImportPackageHandler(File zipFile, String dataFileEncoding)
{
this.file = zipFile;
this.dataFileEncoding = dataFileEncoding;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImportPackageHandler#startImport()
*/
public void startImport()
{
log("Importing from zip file " + file.getAbsolutePath());
try
{
zipFile = new ZipFile(file);
}
catch(IOException e)
{
throw new ImporterException("Failed to read zip file due to " + e.getMessage(), e);
}
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImportPackageHandler#getDataStream()
*/
public Reader getDataStream()
{
try
{
// find data file
InputStream dataStream = null;
Enumeration entries = zipFile.entries();
while(entries.hasMoreElements())
{
ZipEntry entry = (ZipEntry)entries.nextElement();
if (!entry.isDirectory())
{
if (entry.getName().endsWith(".xml"))
{
dataStream = zipFile.getInputStream(entry);
}
}
}
// oh dear, there's no data file
if (dataStream == null)
{
throw new ImporterException("Failed to find data file within zip package");
}
Reader inputReader = (dataFileEncoding == null) ? new InputStreamReader(dataStream) : new InputStreamReader(dataStream, dataFileEncoding);
return new BufferedReader(inputReader);
}
catch(UnsupportedEncodingException e)
{
throw new ImporterException("Encoding " + dataFileEncoding + " is not supported");
}
catch(IOException e)
{
throw new ImporterException("Failed to open data file within zip package due to " + e.getMessage());
}
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImportStreamHandler#importStream(java.lang.String)
*/
public InputStream importStream(String content)
{
ZipEntry zipEntry = zipFile.getEntry(content);
if (zipEntry == null)
{
throw new ImporterException("Failed to find content " + content + " within zip package");
}
try
{
return zipFile.getInputStream(zipEntry);
}
catch (IOException e)
{
throw new ImporterException("Failed to open content " + content + " within zip package due to " + e.getMessage(), e);
}
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImportPackageHandler#endImport()
*/
public void endImport()
{
}
/**
* Log Import Message
*
* @param message message to log
*/
protected void log(String message)
{
}
}

View File

@@ -0,0 +1,153 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import java.io.InputStream;
import org.alfresco.util.ParameterCheck;
import org.xml.sax.Attributes;
import org.xml.sax.ErrorHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* Base Import Content Handler
*/
public class DefaultContentHandler
implements ImportContentHandler, ErrorHandler
{
private ImportContentHandler targetHandler = null;
private Importer importer = null;
public DefaultContentHandler(ImportContentHandler targetHandler)
{
ParameterCheck.mandatory("targetHandler", targetHandler);
this.targetHandler = targetHandler;
}
public void setImporter(Importer importer)
{
this.importer = importer;
this.targetHandler.setImporter(importer);
}
public InputStream importStream(String content)
{
return targetHandler.importStream(content);
}
public void setDocumentLocator(Locator locator)
{
targetHandler.setDocumentLocator(locator);
}
public void startDocument() throws SAXException
{
importer.start();
targetHandler.startDocument();
}
public void endDocument() throws SAXException
{
try
{
targetHandler.endDocument();
}
finally
{
importer.end();
}
}
public void startPrefixMapping(String prefix, String uri) throws SAXException
{
targetHandler.startPrefixMapping(prefix, uri);
}
public void endPrefixMapping(String prefix) throws SAXException
{
targetHandler.endPrefixMapping(prefix);
}
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException
{
targetHandler.startElement(uri, localName, qName, atts);
}
public void endElement(String uri, String localName, String qName) throws SAXException
{
targetHandler.endElement(uri, localName, qName);
}
public void characters(char[] ch, int start, int length) throws SAXException
{
targetHandler.characters(ch, start, length);
}
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
{
targetHandler.ignorableWhitespace(ch, start, length);
}
public void processingInstruction(String target, String data) throws SAXException
{
targetHandler.processingInstruction(target, data);
}
public void skippedEntity(String name) throws SAXException
{
targetHandler.skippedEntity(name);
}
public void error(SAXParseException exception) throws SAXException
{
try
{
targetHandler.error(exception);
}
finally
{
importer.error(exception);
}
}
public void fatalError(SAXParseException exception) throws SAXException
{
try
{
targetHandler.error(exception);
}
finally
{
importer.error(exception);
}
}
public void warning(SAXParseException exception) throws SAXException
{
targetHandler.warning(exception);
}
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import org.alfresco.service.cmr.view.ImportPackageHandler;
import org.alfresco.service.cmr.view.ImporterException;
/**
* Handler for importing Repository content streams from file system
*
* @author David Caruana
*/
public class FileImportPackageHandler
implements ImportPackageHandler
{
protected File sourceDir;
protected File dataFile;
protected String dataFileEncoding;
/**
* Construct
*
* @param sourceDir
* @param dataFile
* @param dataFileEncoding
*/
public FileImportPackageHandler(File sourceDir, File dataFile, String dataFileEncoding)
{
this.sourceDir = sourceDir;
this.dataFile = new File(sourceDir, dataFile.getPath());
this.dataFileEncoding = dataFileEncoding;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImportPackageHandler#startImport()
*/
public void startImport()
{
log("Importing from package " + dataFile.getAbsolutePath());
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImportPackageHandler#getDataStream()
*/
public Reader getDataStream()
{
try
{
InputStream inputStream = new FileInputStream(dataFile);
Reader inputReader = (dataFileEncoding == null) ? new InputStreamReader(inputStream) : new InputStreamReader(inputStream, dataFileEncoding);
return new BufferedReader(inputReader);
}
catch(UnsupportedEncodingException e)
{
throw new ImporterException("Encoding " + dataFileEncoding + " is not supported");
}
catch(IOException e)
{
throw new ImporterException("Failed to read package " + dataFile.getAbsolutePath() + " due to " + e.getMessage());
}
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImportStreamHandler#importStream(java.lang.String)
*/
public InputStream importStream(String content)
{
File fileURL = new File(content);
if (fileURL.isAbsolute() == false)
{
fileURL = new File(sourceDir, content);
}
try
{
return new FileInputStream(fileURL);
}
catch(IOException e)
{
throw new ImporterException("Failed to read content url " + content + " from file " + fileURL.getAbsolutePath());
}
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImportPackageHandler#endImport()
*/
public void endImport()
{
}
/**
* Log Import Message
*
* @param message message to log
*/
protected void log(String message)
{
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import java.io.File;
import java.io.FileFilter;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Interface to load files and directories into the hub.
* All will be created as new - there is no detection if a file exists or has changed etc..
*
* @author andyh
*/
public interface FileImporter
{
/**
* Load a file or directory into the repository
*
* @param container - the node into which to insert the file or directory
* @param file - the start point for the import
* @param recurse - if the start point is a directoty then recurse
* @return Returns the number of successfully imported files and directories
* @throws FileImporterException
*/
public int loadFile(NodeRef container, File file, boolean recurse) throws FileImporterException;
/**
* Load all files or directories that match the file filter in the given directory
*
* @param container
* @param file
* @param filter
* @param recurse
* @return Returns the number of successfully imported files and directories
* @throws FileImporterException
*/
public int loadFile(NodeRef container, File file, FileFilter filter, boolean recurse) throws FileImporterException;
/**
* Load a single file or directory without any recursion
*
* @param container
* @param file
* @return Returns the number of successfully imported files and directories
* @throws FileImporterException
*/
public int loadFile(NodeRef container, File file) throws FileImporterException;
public int loadNamedFile(NodeRef container, File file, boolean recurse, String name) throws FileImporterException;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import org.alfresco.error.AlfrescoRuntimeException;
public class FileImporterException extends AlfrescoRuntimeException
{
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 3544669594364490545L;
public FileImporterException(String msg)
{
super(msg);
}
public FileImporterException(String msg, Throwable cause)
{
super(msg, cause);
}
}

View File

@@ -0,0 +1,294 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Simple import of content into the repository
*
* @author andyh
*/
public class FileImporterImpl implements FileImporter
{
private static Log logger = LogFactory.getLog(FileImporterImpl.class);
private AuthenticationService authenticationService;
private NodeService nodeService;
private DictionaryService dictionaryService;
private ContentService contentService;
private MimetypeService mimetypeService;
public FileImporterImpl()
{
super();
}
public int loadFile(NodeRef container, File file, boolean recurse) throws FileImporterException
{
Counter counter = new Counter();
create(counter, container, file, null, recurse, null);
return counter.getCount();
}
public int loadNamedFile(NodeRef container, File file, boolean recurse, String name) throws FileImporterException
{
Counter counter = new Counter();
create(counter, container, file, null, recurse, name);
return counter.getCount();
}
public int loadFile(NodeRef container, File file, FileFilter filter, boolean recurse) throws FileImporterException
{
Counter counter = new Counter();
create(counter, container, file, filter, recurse, null);
return counter.getCount();
}
public int loadFile(NodeRef container, File file) throws FileImporterException
{
Counter counter = new Counter();
create(counter, container, file, null, false, null);
return counter.getCount();
}
/** Helper class for mutable int */
private static class Counter
{
private int count = 0;
public void increment()
{
count++;
}
public int getCount()
{
return count;
}
}
private NodeRef create(Counter counter, NodeRef container, File file, FileFilter filter, boolean recurse, String containerName)
{
if(containerName != null)
{
NodeRef newContainer = createDirectory(container, containerName, containerName);
return create(counter, newContainer, file, filter, recurse, null);
}
if (file.isDirectory())
{
NodeRef directoryNodeRef = createDirectory(container, file);
counter.increment();
if(recurse)
{
File[] files = ((filter == null) ? file.listFiles() : file.listFiles(filter));
for(int i = 0; i < files.length; i++)
{
create(counter, directoryNodeRef, files[i], filter, recurse, null);
}
}
return directoryNodeRef;
}
else
{
counter.increment();
return createFile(container, file);
}
}
/**
* Get the type of child association that should be created.
*
* @param parentNodeRef the parent
* @return Returns the appropriate child association type qualified name for the type of the
* parent. Null will be returned if it can't be determined.
*/
private QName getAssocTypeQName(NodeRef parentNodeRef)
{
// check the parent node's type to determine which association to use
QName parentNodeTypeQName = nodeService.getType(parentNodeRef);
QName assocTypeQName = null;
if (dictionaryService.isSubClass(parentNodeTypeQName, ContentModel.TYPE_CONTAINER))
{
// it may be a root node or something similar
assocTypeQName = ContentModel.ASSOC_CHILDREN;
}
else if (dictionaryService.isSubClass(parentNodeTypeQName, ContentModel.TYPE_FOLDER))
{
// more like a directory
assocTypeQName = ContentModel.ASSOC_CONTAINS;
}
return assocTypeQName;
}
private NodeRef createFile(NodeRef parentNodeRef, File file)
{
// check the parent node's type to determine which association to use
QName assocTypeQName = getAssocTypeQName(parentNodeRef);
if (assocTypeQName == null)
{
throw new IllegalArgumentException(
"Unable to create file. " +
"Parent type is inappropriate: " + nodeService.getType(parentNodeRef));
}
// create properties for content type
Map<QName, Serializable> contentProps = new HashMap<QName, Serializable>(3, 1.0f);
contentProps.put(ContentModel.PROP_NAME, file.getName());
contentProps.put(
ContentModel.PROP_CONTENT,
new ContentData(null, mimetypeService.guessMimetype(file.getName()), 0L, "UTF-8"));
String currentUser = authenticationService.getCurrentUserName();
contentProps.put(ContentModel.PROP_CREATOR, currentUser == null ? "unknown" : currentUser);
// create the node to represent the node
String assocName = QName.createValidLocalName(file.getName());
ChildAssociationRef assocRef = this.nodeService.createNode(
parentNodeRef,
assocTypeQName,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, assocName),
ContentModel.TYPE_CONTENT, contentProps);
NodeRef fileNodeRef = assocRef.getChildRef();
if (logger.isDebugEnabled())
logger.debug("Created file node for file: " + file.getName());
// apply the titled aspect - title and description
Map<QName, Serializable> titledProps = new HashMap<QName, Serializable>(5);
titledProps.put(ContentModel.PROP_TITLE, file.getName());
titledProps.put(ContentModel.PROP_DESCRIPTION, file.getPath());
this.nodeService.addAspect(fileNodeRef, ContentModel.ASPECT_TITLED, titledProps);
if (logger.isDebugEnabled())
logger.debug("Added titled aspect with properties: " + titledProps);
// get a writer for the content and put the file
ContentWriter writer = contentService.getWriter(fileNodeRef, ContentModel.PROP_CONTENT, true);
try
{
writer.putContent(new BufferedInputStream(new FileInputStream(file)));
}
catch (ContentIOException e)
{
throw new FileImporterException("Failed to load content from "+file.getPath(), e);
}
catch (FileNotFoundException e)
{
throw new FileImporterException("Failed to load content (file not found) "+file.getPath(), e);
}
return fileNodeRef;
}
private NodeRef createDirectory(NodeRef parentNodeRef, File file)
{
return createDirectory(parentNodeRef, file.getName(), file.getPath());
}
private NodeRef createDirectory(NodeRef parentNodeRef, String name, String path)
{
// check the parent node's type to determine which association to use
QName assocTypeQName = getAssocTypeQName(parentNodeRef);
if (assocTypeQName == null)
{
throw new IllegalArgumentException(
"Unable to create directory. " +
"Parent type is inappropriate: " + nodeService.getType(parentNodeRef));
}
String qname = QName.createValidLocalName(name);
ChildAssociationRef assocRef = this.nodeService.createNode(
parentNodeRef,
assocTypeQName,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, qname),
ContentModel.TYPE_FOLDER);
NodeRef nodeRef = assocRef.getChildRef();
// set the name property on the node
this.nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, name);
if (logger.isDebugEnabled())
logger.debug("Created folder node with name: " + name);
// apply the uifacets aspect - icon, title and description props
Map<QName, Serializable> uiFacetsProps = new HashMap<QName, Serializable>(5);
uiFacetsProps.put(ContentModel.PROP_ICON, "space-icon-default");
uiFacetsProps.put(ContentModel.PROP_TITLE, name);
uiFacetsProps.put(ContentModel.PROP_DESCRIPTION, path);
this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_UIFACETS, uiFacetsProps);
if (logger.isDebugEnabled())
logger.debug("Added uifacets aspect with properties: " + uiFacetsProps);
return nodeRef;
}
protected void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
protected void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
protected void setMimetypeService(MimetypeService mimetypeService)
{
this.mimetypeService = mimetypeService;
}
protected void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
}

View File

@@ -0,0 +1,313 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.util.List;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.TempFileProvider;
import org.springframework.context.ApplicationContext;
public class FileImporterTest extends TestCase
{
static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private NodeService nodeService;
private SearchService searchService;
private DictionaryService dictionaryService;
private ContentService contentService;
private AuthenticationService authenticationService;
private AuthenticationComponent authenticationComponent;
private MimetypeService mimetypeService;
private NamespaceService namespaceService;
private ServiceRegistry serviceRegistry;
private NodeRef rootNodeRef;
private SearchService searcher;
public FileImporterTest()
{
super();
}
public FileImporterTest(String arg0)
{
super(arg0);
}
public void setUp()
{
serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
searcher = serviceRegistry.getSearchService();
nodeService = serviceRegistry.getNodeService();
searchService = serviceRegistry.getSearchService();
dictionaryService = serviceRegistry.getDictionaryService();
contentService = serviceRegistry.getContentService();
authenticationService = (AuthenticationService) ctx.getBean("authenticationService");
authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
mimetypeService = serviceRegistry.getMimetypeService();
namespaceService = serviceRegistry.getNamespaceService();
authenticationComponent.setSystemUserAsCurrentUser();
StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
rootNodeRef = nodeService.getRootNode(storeRef);
}
private FileImporter createFileImporter()
{
FileImporterImpl fileImporter = new FileImporterImpl();
fileImporter.setAuthenticationService(authenticationService);
fileImporter.setContentService(contentService);
fileImporter.setMimetypeService(mimetypeService);
fileImporter.setNodeService(nodeService);
fileImporter.setDictionaryService(dictionaryService);
return fileImporter;
}
public void testCreateFile() throws Exception
{
FileImporter fileImporter = createFileImporter();
File file = AbstractContentTransformerTest.loadQuickTestFile("xml");
fileImporter.loadFile(rootNodeRef, file);
}
public void testLoadRootNonRecursive1()
{
FileImporter fileImporter = createFileImporter();
URL url = this.getClass().getClassLoader().getResource("");
File root = new File(url.getFile());
int count = fileImporter.loadFile(rootNodeRef, new File(url.getFile()));
assertEquals("Expected to load a single file", 1, count);
}
public void testLoadRootNonRecursive2()
{
FileImporter fileImporter = createFileImporter();
URL url = this.getClass().getClassLoader().getResource("");
File root = new File(url.getFile());
int count = fileImporter.loadFile(rootNodeRef, root, null, false);
assertEquals("Expected to load a single file", 1, count);
}
public void testLoadXMLFiles()
{
FileImporter fileImporter = createFileImporter();
URL url = this.getClass().getClassLoader().getResource("");
FileFilter filter = new XMLFileFilter();
fileImporter.loadFile(rootNodeRef, new File(url.getFile()), filter, true);
}
public void testLoadSourceTestResources()
{
FileImporter fileImporter = createFileImporter();
URL url = this.getClass().getClassLoader().getResource("quick");
FileFilter filter = new QuickFileFilter();
fileImporter.loadFile(rootNodeRef, new File(url.getFile()), filter, true);
}
private static class XMLFileFilter implements FileFilter
{
public boolean accept(File file)
{
return file.getName().endsWith(".xml");
}
}
private static class QuickFileFilter implements FileFilter
{
public boolean accept(File file)
{
return file.getName().startsWith("quick");
}
}
/**
* @param args
* <ol>
* <li>StoreRef
* <li>Store Path
* <li>Directory
* <li>Optional maximum time in seconds for node loading
* </ol>
* @throws SystemException
* @throws NotSupportedException
* @throws HeuristicRollbackException
* @throws HeuristicMixedException
* @throws RollbackException
* @throws IllegalStateException
* @throws SecurityException
*/
public static final void main(String[] args) throws Exception
{
int exitCode = 0;
int grandTotal = 0;
int count = 0;
int target = Integer.parseInt(args[4]);
while (count < target)
{
File directory = TempFileProvider.getTempDir();
File[] files = directory.listFiles();
System.out.println("Start temp file count = " + files.length);
count++;
FileImporterTest test = new FileImporterTest();
test.setUp();
test.authenticationComponent.setSystemUserAsCurrentUser();
TransactionService transactionService = test.serviceRegistry.getTransactionService();
UserTransaction tx = transactionService.getUserTransaction();
tx.begin();
try
{
StoreRef spacesStore = new StoreRef(args[0]);
if (!test.nodeService.exists(spacesStore))
{
test.nodeService.createStore(spacesStore.getProtocol(), spacesStore.getIdentifier());
}
NodeRef storeRoot = test.nodeService.getRootNode(spacesStore);
List<NodeRef> location = test.searchService.selectNodes(
storeRoot,
args[1],
null,
test.namespaceService,
false);
if (location.size() == 0)
{
throw new AlfrescoRuntimeException(
"Root node not found, " +
args[1] +
" not found in store, " +
storeRoot);
}
long start = System.nanoTime();
int importCount = test.createFileImporter().loadNamedFile(location.get(0), new File(args[2]), true, args[3]+count);
grandTotal += importCount;
long end = System.nanoTime();
long first = end-start;
System.out.println("Created in: " + ((end - start) / 1000000.0) + "ms");
start = System.nanoTime();
tx.commit();
end = System.nanoTime();
long second = end-start;
System.out.println("Committed in: " + ((end - start) / 1000000.0) + "ms");
double total = ((first+second)/1000000.0);
System.out.println("Grand Total: "+ grandTotal);
System.out.println("Count: "+ count + "ms");
System.out.println("Imported: " + importCount + " files or directories");
System.out.println("Average: " + (importCount / (total / 1000.0)) + " files per second");
directory = TempFileProvider.getTempDir();
files = directory.listFiles();
System.out.println("End temp file count = " + files.length);
tx = transactionService.getUserTransaction();
tx.begin();
SearchParameters sp = new SearchParameters();
sp.setLanguage("lucene");
sp.setQuery("ISNODE:T");
sp.addStore(spacesStore);
start = System.nanoTime();
ResultSet rs = test.searchService.query(sp);
end = System.nanoTime();
System.out.println("Find all in: " + ((end - start) / 1000000.0) + "ms");
System.out.println(" = "+rs.length() +"\n\n");
rs.close();
sp = new SearchParameters();
sp.setLanguage("lucene");
sp.setQuery("TEXT:\"andy\"");
sp.addStore(spacesStore);
start = System.nanoTime();
rs = test.searchService.query(sp);
end = System.nanoTime();
System.out.println("Find andy in: " + ((end - start) / 1000000.0) + "ms");
System.out.println(" = "+rs.length() +"\n\n");
rs.close();
sp = new SearchParameters();
sp.setLanguage("lucene");
sp.setQuery("TYPE:\"" + ContentModel.TYPE_CONTENT.toString() + "\"");
sp.addStore(spacesStore);
start = System.nanoTime();
rs = test.searchService.query(sp);
end = System.nanoTime();
System.out.println("Find content in: " + ((end - start) / 1000000.0) + "ms");
System.out.println(" = "+rs.length() +"\n\n");
rs.close();
sp = new SearchParameters();
sp.setLanguage("lucene");
sp.setQuery("PATH:\"/*/*/*\"");
sp.addStore(spacesStore);
start = System.nanoTime();
rs = test.searchService.query(sp);
end = System.nanoTime();
System.out.println("Find /*/*/* in: " + ((end - start) / 1000000.0) + "ms");
System.out.println(" = "+rs.length() +"\n\n");
rs.close();
tx.commit();
}
catch (Throwable e)
{
tx.rollback();
e.printStackTrace();
exitCode = 1;
}
//System.exit(exitCode);
}
System.exit(0);
}
}

View File

@@ -0,0 +1,15 @@
package org.alfresco.repo.importer;
import java.io.InputStream;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
public interface ImportContentHandler extends ContentHandler, ErrorHandler
{
public void setImporter(Importer importer);
public InputStream importStream(String content);
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Description of node to import.
*
* @author David Caruana
*
*/
public interface ImportNode
{
/**
* @return the parent context
*/
public ImportParent getParentContext();
/**
* @return the type definition
*/
public TypeDefinition getTypeDefinition();
/**
* @return the node ref
*/
public NodeRef getNodeRef();
/**
* @return the child name
*/
public String getChildName();
/**
* Gets all properties for the node
*
* @return the properties
*/
public Map<QName,Serializable> getProperties();
/**
* Gets all property datatypes for the node
*
* @return the property datatypes
*/
public Map<QName,DataTypeDefinition> getPropertyDatatypes();
/**
* @return the aspects of this node
*/
public Set<QName> getNodeAspects();
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Description of parent for node to import.
*
* @author David Caruana
*
*/
public interface ImportParent
{
/**
* @return the parent ref
*/
/*package*/ NodeRef getParentRef();
/**
* @return the child association type
*/
/*package*/ QName getAssocType();
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import java.util.Map;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* The Importer interface encapusulates the strategy for importing
* a node into the Repository.
*
* @author David Caruana
*/
public interface Importer
{
/**
* @return the root node to import into
*/
public NodeRef getRootRef();
/**
* @return the root child association type to import under
*/
public QName getRootAssocType();
/**
* Signal start of import
*/
public void start();
/**
* Signal end of import
*/
public void end();
/**
* Signal import error
*/
public void error(Throwable e);
/**
* Import meta-data
*/
public void importMetaData(Map<QName, String> properties);
/**
* Import a node
*
* @param node the node description
* @return the node ref of the imported node
*/
public NodeRef importNode(ImportNode node);
/**
* Signal completion of node import
*
* @param nodeRef the node ref of the imported node
*/
public void childrenImported(NodeRef nodeRef);
}

View File

@@ -0,0 +1,507 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.view.ImporterBinding;
import org.alfresco.service.cmr.view.ImporterException;
import org.alfresco.service.cmr.view.ImporterProgress;
import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.view.Location;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Bootstrap Repository store.
*
* @author David Caruana
*/
public class ImporterBootstrap
{
// View Properties (used in setBootstrapViews)
public static final String VIEW_PATH_PROPERTY = "path";
public static final String VIEW_CHILDASSOCTYPE_PROPERTY = "childAssocType";
public static final String VIEW_MESSAGES_PROPERTY = "messages";
public static final String VIEW_LOCATION_VIEW = "location";
public static final String VIEW_ENCODING = "encoding";
// Logger
private static final Log logger = LogFactory.getLog(ImporterBootstrap.class);
// Dependencies
private boolean allowWrite = true;
private TransactionService transactionService;
private NamespaceService namespaceService;
private NodeService nodeService;
private ImporterService importerService;
private List<Properties> bootstrapViews;
private StoreRef storeRef = null;
private List<String> mustNotExistStoreUrls = null;
private Properties configuration = null;
private String strLocale = null;
private Locale locale = null;
private AuthenticationComponent authenticationComponent;
/**
* Set whether we write or not
*
* @param write true (default) if the import must go ahead, otherwise no import will occur
*/
public void setAllowWrite(boolean write)
{
this.allowWrite = write;
}
/**
* Sets the Transaction Service
*
* @param userTransaction the transaction service
*/
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
/**
* Sets the namespace service
*
* @param namespaceService the namespace service
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* Sets the node service
*
* @param nodeService the node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Sets the importer service
*
* @param importerService the importer service
*/
public void setImporterService(ImporterService importerService)
{
this.importerService = importerService;
}
/**
* Set the authentication component
*
* @param authenticationComponent
*/
public void setAuthenticationComponent(AuthenticationComponent authenticationComponent)
{
this.authenticationComponent = authenticationComponent;
}
/**
* Sets the bootstrap views
*
* @param bootstrapViews
*/
public void setBootstrapViews(List<Properties> bootstrapViews)
{
this.bootstrapViews = bootstrapViews;
}
/**
* Sets the Store Ref to bootstrap into
*
* @param storeUrl
*/
public void setStoreUrl(String storeUrl)
{
this.storeRef = new StoreRef(storeUrl);
}
/**
* If any of the store urls exist, the bootstrap does not take place
*
* @param storeUrls the list of store urls to check
*/
public void setMustNotExistStoreUrls(List<String> storeUrls)
{
this.mustNotExistStoreUrls = storeUrls;
}
/**
* Gets the Store Reference
*
* @return store reference
*/
public StoreRef getStoreRef()
{
return this.storeRef;
}
/**
* Sets the Configuration values for binding place holders
*
* @param configuration
*/
public void setConfiguration(Properties configuration)
{
this.configuration = configuration;
}
/**
* Gets the Configuration values for binding place holders
*
* @return configuration
*/
public Properties getConfiguration()
{
return configuration;
}
/**
* Sets the Locale
*
* @param locale (language_country_variant)
*/
public void setLocale(String locale)
{
// construct locale
StringTokenizer t = new StringTokenizer(locale, "_");
int tokens = t.countTokens();
if (tokens == 1)
{
this.locale = new Locale(locale);
}
else if (tokens == 2)
{
this.locale = new Locale(t.nextToken(), t.nextToken());
}
else if (tokens == 3)
{
this.locale = new Locale(t.nextToken(), t.nextToken(), t.nextToken());
}
// store original
strLocale = locale;
}
/**
* Get Locale
*
* @return locale
*/
public String getLocale()
{
return strLocale;
}
/**
* Boostrap the Repository
*/
public void bootstrap()
{
if (transactionService == null)
{
throw new ImporterException("Transaction Service must be provided");
}
if (namespaceService == null)
{
throw new ImporterException("Namespace Service must be provided");
}
if (nodeService == null)
{
throw new ImporterException("Node Service must be provided");
}
if (importerService == null)
{
throw new ImporterException("Importer Service must be provided");
}
if (storeRef == null)
{
throw new ImporterException("Store URL must be provided");
}
UserTransaction userTransaction = transactionService.getUserTransaction();
authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
try
{
userTransaction.begin();
// check the repository exists, create if it doesn't
if (!performBootstrap())
{
if (logger.isDebugEnabled())
logger.debug("Store exists - bootstrap ignored: " + storeRef);
userTransaction.rollback();
}
else if (!allowWrite)
{
// we're in read-only node
logger.warn("Store does not exist, but mode is read-only: " + storeRef);
userTransaction.rollback();
}
else
{
// create the store
storeRef = nodeService.createStore(storeRef.getProtocol(), storeRef.getIdentifier());
if (logger.isDebugEnabled())
logger.debug("Created store: " + storeRef);
// bootstrap the store contents
if (bootstrapViews != null)
{
for (Properties bootstrapView : bootstrapViews)
{
// Create input stream reader onto view file
String view = bootstrapView.getProperty(VIEW_LOCATION_VIEW);
if (view == null || view.length() == 0)
{
throw new ImporterException("View file location must be provided");
}
String encoding = bootstrapView.getProperty(VIEW_ENCODING);
Reader viewReader = getReader(view, encoding);
// Create import location
Location importLocation = new Location(storeRef);
String path = bootstrapView.getProperty(VIEW_PATH_PROPERTY);
if (path != null && path.length() > 0)
{
importLocation.setPath(path);
}
String childAssocType = bootstrapView.getProperty(VIEW_CHILDASSOCTYPE_PROPERTY);
if (childAssocType != null && childAssocType.length() > 0)
{
importLocation.setChildAssocType(QName.createQName(childAssocType, namespaceService));
}
// Create import binding
BootstrapBinding binding = new BootstrapBinding();
binding.setConfiguration(configuration);
String messages = bootstrapView.getProperty(VIEW_MESSAGES_PROPERTY);
if (messages != null && messages.length() > 0)
{
Locale bindingLocale = (locale == null) ? I18NUtil.getLocale() : locale;
ResourceBundle bundle = ResourceBundle.getBundle(messages, bindingLocale);
binding.setResourceBundle(bundle);
}
// Now import...
importerService.importView(viewReader, importLocation, binding, new BootstrapProgress());
}
}
userTransaction.commit();
}
}
catch(Throwable e)
{
// rollback the transaction
try { if (userTransaction != null) {userTransaction.rollback();} } catch (Exception ex) {}
try {authenticationComponent.clearCurrentSecurityContext(); } catch (Exception ex) {}
throw new AlfrescoRuntimeException("Bootstrap failed", e);
}
finally
{
authenticationComponent.clearCurrentSecurityContext();
}
}
/**
* Get a Reader onto an XML view
*
* @param view the view location
* @param encoding the encoding of the view
* @return the reader
*/
private Reader getReader(String view, String encoding)
{
// Get Input Stream
InputStream viewStream = getClass().getClassLoader().getResourceAsStream(view);
if (viewStream == null)
{
throw new ImporterException("Could not find view file " + view);
}
// Wrap in buffered reader
try
{
InputStreamReader inputReader = (encoding == null) ? new InputStreamReader(viewStream) : new InputStreamReader(viewStream, encoding);
BufferedReader reader = new BufferedReader(inputReader);
return reader;
}
catch (UnsupportedEncodingException e)
{
throw new ImporterException("Could not create reader for view " + view + " as encoding " + encoding + " is not supported");
}
}
/**
* Bootstrap Binding
*/
private class BootstrapBinding implements ImporterBinding
{
private Properties configuration = null;
private ResourceBundle resourceBundle = null;
/**
* Set Import Configuration
*
* @param configuration
*/
public void setConfiguration(Properties configuration)
{
this.configuration = configuration;
}
/**
* Get Import Configuration
*
* @return configuration
*/
public Properties getConfiguration()
{
return this.configuration;
}
/**
* Set Resource Bundle
*
* @param resourceBundle
*/
public void setResourceBundle(ResourceBundle resourceBundle)
{
this.resourceBundle = resourceBundle;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.view.ImporterBinding#getValue(java.lang.String)
*/
public String getValue(String key)
{
String value = null;
if (configuration != null)
{
value = configuration.getProperty(key);
}
if (value == null && resourceBundle != null)
{
value = resourceBundle.getString(key);
}
return value;
}
}
/**
* Bootstrap Progress (debug logging)
*/
private class BootstrapProgress implements ImporterProgress
{
/* (non-Javadoc)
* @see org.alfresco.repo.importer.Progress#nodeCreated(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName)
*/
public void nodeCreated(NodeRef nodeRef, NodeRef parentRef, QName assocName, QName childName)
{
if (logger.isDebugEnabled())
logger.debug("Created 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)
*/
public void contentCreated(NodeRef nodeRef, String sourceUrl)
{
if (logger.isDebugEnabled())
logger.debug("Imported content from " + sourceUrl + " into node " + nodeRef);
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.Progress#propertySet(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, java.io.Serializable)
*/
public void propertySet(NodeRef nodeRef, QName property, Serializable value)
{
if (logger.isDebugEnabled())
logger.debug("Property " + property + " set to value " + value + " on node " + nodeRef);
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.Progress#aspectAdded(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
*/
public void aspectAdded(NodeRef nodeRef, QName aspect)
{
if (logger.isDebugEnabled())
logger.debug("Added aspect " + aspect + " to node " + nodeRef);
}
}
/**
* Determine if bootstrap should take place
*
* @return true => yes, it should
*/
private boolean performBootstrap()
{
if (nodeService.exists(storeRef))
{
return false;
}
if (mustNotExistStoreUrls != null)
{
for (String storeUrl : mustNotExistStoreUrls)
{
StoreRef storeRef = new StoreRef(storeUrl);
if (nodeService.exists(storeRef))
{
return false;
}
}
}
return true;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.view.ImporterProgress;
import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.view.Location;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.BaseSpringTest;
import org.alfresco.util.debug.NodeStoreInspector;
public class ImporterComponentTest extends BaseSpringTest
{
private ImporterService importerService;
private ImporterBootstrap importerBootstrap;
private NodeService nodeService;
private StoreRef storeRef;
private AuthenticationComponent authenticationComponent;
@Override
protected void onSetUpInTransaction() throws Exception
{
nodeService = (NodeService)applicationContext.getBean(ServiceRegistry.NODE_SERVICE.getLocalName());
importerService = (ImporterService)applicationContext.getBean(ServiceRegistry.IMPORTER_SERVICE.getLocalName());
importerBootstrap = (ImporterBootstrap)applicationContext.getBean("importerBootstrap");
this.authenticationComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent");
this.authenticationComponent.setSystemUserAsCurrentUser();
// Create the store
this.storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
}
@Override
protected void onTearDownInTransaction()
{
authenticationComponent.clearCurrentSecurityContext();
super.onTearDownInTransaction();
}
public void testImport()
throws Exception
{
InputStream test = getClass().getClassLoader().getResourceAsStream("org/alfresco/repo/importer/importercomponent_test.xml");
InputStreamReader testReader = new InputStreamReader(test, "UTF-8");
TestProgress testProgress = new TestProgress();
Location location = new Location(storeRef);
importerService.importView(testReader, location, null, testProgress);
System.out.println(NodeStoreInspector.dumpNodeStore(nodeService, storeRef));
}
public void testBootstrap()
{
StoreRef bootstrapStoreRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
importerBootstrap.setStoreUrl(bootstrapStoreRef.toString());
importerBootstrap.bootstrap();
authenticationComponent.setSystemUserAsCurrentUser();
System.out.println(NodeStoreInspector.dumpNodeStore(nodeService, bootstrapStoreRef));
}
private static class TestProgress implements ImporterProgress
{
public void nodeCreated(NodeRef nodeRef, NodeRef parentRef, QName assocName, QName childName)
{
System.out.println("TestProgress: created 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);
}
public void propertySet(NodeRef nodeRef, QName property, Serializable value)
{
System.out.println("TestProgress: set property " + property + " on node " + nodeRef + " to value " + value);
}
public void aspectAdded(NodeRef nodeRef, QName aspect)
{
System.out.println("TestProgress: added aspect " + aspect + " to node ");
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer;
import java.io.Reader;
/**
* This interface represents the contract between the importer service and a
* parser (which is responsible for parsing the input stream and extracting
* node descriptions).
*
* The parser interacts with the passed importer to import nodes into the
* Repository.
*
* @author David Caruana
*/
public interface Parser
{
/**
* Parse nodes from specified input stream and import via the provided importer
*
* @param viewReader
* @param importer
*/
public void parse(Reader viewReader, Importer importer);
}

View File

@@ -0,0 +1,74 @@
<!-- Note: The import will be performed relative to a specific path specified at import
time -->
<view:view xmlns:view="http://www.alfresco.org/view/repository/1.0"
xmlns:cm="http://www.alfresco.org/model/content/1.0"
xmlns="">
<view:metadata>
<view:exportBy>unknown</view:exportBy>
<view:exportDate>2005-10-19T19:18:01.387+01:00</view:exportDate>
<view:exporterVersion>1.0.0 (rc1b)</view:exporterVersion>
<view:exportOf>/system</view:exportOf>
</view:metadata>
<cm:systemfolder view:childName="system">
<cm:name>System</cm:name>
<cm:orderedchildren>true</cm:orderedchildren>
<cm:contains>
<cm:systemfolder view:childName="cm:people folder">
<view:aspects>
<cm:auditable/>
</view:aspects>
<view:properties>
<cm:name>`¬¦!£$%^&amp;()-_=+tnu0000[]{};'#@~,</cm:name>
<cm:creator>testuser</cm:creator>
<cm:modifier>testuser</cm:modifier>
<cm:notinmodel>
<view:value view:datatype="d:text">dfsdfsdf</view:value>
</cm:notinmodel>
</view:properties>
<view:associations>
<cm:contains>
<cm:person view:childName="cm:fredb">
<view:aspects/>
<view:properties>
<cm:userName>${username}</cm:userName>
<cm:firstName>Fred</cm:firstName>
<cm:lastName>Bloggs</cm:lastName>
<cm:homeFolder>../../cm:people_x0020_folder</cm:homeFolder>
</view:properties>
</cm:person>
</cm:contains>
</view:associations>
</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: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>
</view:view>

View File

@@ -0,0 +1 @@
A test import file

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer.view;
import org.alfresco.repo.importer.Importer;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.namespace.QName;
/**
* Maintains state about the currently imported element.
*
* @author David Caruana
*
*/
public class ElementContext
{
// Dictionary Service
private DictionaryService dictionary;
// Element Name
private QName elementName;
// Importer
private Importer importer;
/**
* Construct
*
* @param dictionary
* @param elementName
* @param progress
*/
public ElementContext(QName elementName, DictionaryService dictionary, Importer importer)
{
this.elementName = elementName;
this.dictionary = dictionary;
this.importer = importer;
}
/**
* @return the element name
*/
public QName getElementName()
{
return elementName;
}
/**
* @return the dictionary service
*/
public DictionaryService getDictionaryService()
{
return dictionary;
}
/**
* @return the importer
*/
public Importer getImporter()
{
return importer;
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer.view;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.service.namespace.QName;
/**
* Represents View Meta Data
*
* @author David Caruana
*/
public class MetaDataContext extends ElementContext
{
private Map<QName, String> properties = new HashMap<QName, String>();
/**
* Construct
*
* @param elementName
* @param dictionary
* @param importer
*/
public MetaDataContext(QName elementName, ElementContext context)
{
super(elementName, context.getDictionaryService(), context.getImporter());
}
/**
* Set meta-data property
*
* @param property property name
* @param value property value
*/
public void setProperty(QName property, String value)
{
properties.put(property, value);
}
/**
* Get meta-data property
*
* @param property property name
* @return property value
*/
public String getProperty(QName property)
{
return properties.get(property);
}
/**
* Get all meta-data properties
*
* @return all meta-data properties
*/
public Map<QName, String> getProperties()
{
return properties;
}
}

View File

@@ -0,0 +1,341 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer.view;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.importer.ImportNode;
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.ClassDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
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.namespace.QName;
/**
* Maintains state about the currently imported node.
*
* @author David Caruana
*
*/
public class NodeContext extends ElementContext
implements ImportNode
{
private ParentContext parentContext;
private NodeRef nodeRef;
private TypeDefinition typeDef;
private String childName;
private Map<QName, AspectDefinition> nodeAspects = new HashMap<QName, AspectDefinition>();
private Map<QName, ChildAssociationDefinition> nodeChildAssocs = new HashMap<QName, ChildAssociationDefinition>();
private Map<QName, Serializable> nodeProperties = new HashMap<QName, Serializable>();
private Map<QName, DataTypeDefinition> propertyDatatypes = new HashMap<QName, DataTypeDefinition>();
/**
* Construct
*
* @param elementName
* @param parentContext
* @param typeDef
*/
public NodeContext(QName elementName, ParentContext parentContext, TypeDefinition typeDef)
{
super(elementName, parentContext.getDictionaryService(), parentContext.getImporter());
this.parentContext = parentContext;
this.typeDef = typeDef;
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#getParentContext()
*/
public ParentContext getParentContext()
{
return parentContext;
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#getTypeDefinition()
*/
public TypeDefinition getTypeDefinition()
{
return typeDef;
}
/**
* Set Type Definition
*
* @param typeDef
*/
public void setTypeDefinition(TypeDefinition typeDef)
{
this.typeDef = typeDef;
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#getNodeRef()
*/
public NodeRef getNodeRef()
{
return nodeRef;
}
/**
* @param nodeRef the node ref
*/
public void setNodeRef(NodeRef nodeRef)
{
this.nodeRef = nodeRef;
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#getChildName()
*/
public String getChildName()
{
return childName;
}
/**
* @param childName the child name
*/
public void setChildName(String childName)
{
this.childName = childName;
}
/**
* Adds a collection property to the node
*
* @param property
*/
public void addPropertyCollection(QName property)
{
// Do not import properties of sys:referenceable or cm:versionable
// TODO: Make this configurable...
PropertyDefinition propDef = getDictionaryService().getProperty(property);
ClassDefinition classDef = (propDef == null) ? null : propDef.getContainerClass();
if (classDef != null)
{
if (classDef.getName().equals(ContentModel.ASPECT_REFERENCEABLE) ||
classDef.getName().equals(ContentModel.ASPECT_VERSIONABLE))
{
return;
}
}
// create collection and assign to property
List<Serializable>values = new ArrayList<Serializable>();
nodeProperties.put(property, (Serializable)values);
}
/**
* Adds a property to the node
*
* @param property the property name
* @param value the property value
*/
public void addProperty(QName property, String value)
{
// Do not import properties of sys:referenceable or cm:versionable
// TODO: Make this configurable...
PropertyDefinition propDef = getDictionaryService().getProperty(property);
ClassDefinition classDef = (propDef == null) ? null : propDef.getContainerClass();
if (classDef != null)
{
if (classDef.getName().equals(ContentModel.ASPECT_REFERENCEABLE) ||
classDef.getName().equals(ContentModel.ASPECT_VERSIONABLE))
{
return;
}
}
// Handle single / multi-valued cases
Serializable newValue = value;
Serializable existingValue = nodeProperties.get(property);
if (existingValue != null)
{
if (existingValue instanceof Collection)
{
// add to existing collection of values
((Collection<Serializable>)existingValue).add(value);
newValue = existingValue;
}
else
{
// convert single to multi-valued
List<Serializable>values = new ArrayList<Serializable>();
values.add((String)existingValue);
values.add(value);
newValue = (Serializable)values;
}
}
nodeProperties.put(property, newValue);
}
/**
* Adds a property datatype to the node
*
* @param property property name
* @param datatype property datatype
*/
public void addDatatype(QName property, DataTypeDefinition datatype)
{
propertyDatatypes.put(property, datatype);
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#getPropertyDatatypes()
*/
public Map<QName, DataTypeDefinition> getPropertyDatatypes()
{
return propertyDatatypes;
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#getProperties()
*/
public Map<QName, Serializable> getProperties()
{
return nodeProperties;
}
/**
* Adds an aspect to the node
*
* @param aspect the aspect
*/
public void addAspect(AspectDefinition aspect)
{
nodeAspects.put(aspect.getName(), aspect);
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportNode#getNodeAspects()
*/
public Set<QName> getNodeAspects()
{
return nodeAspects.keySet();
}
/**
* Determine the type of definition (aspect, property, association) from the
* specified name
*
* @param defName
* @return the dictionary definition
*/
public Object determineDefinition(QName defName)
{
Object def = determineAspect(defName);
if (def == null)
{
def = determineProperty(defName);
if (def == null)
{
def = determineAssociation(defName);
}
}
return def;
}
/**
* Determine if name referes to an aspect
*
* @param defName
* @return
*/
public AspectDefinition determineAspect(QName defName)
{
AspectDefinition def = null;
if (nodeAspects.containsKey(defName) == false)
{
def = getDictionaryService().getAspect(defName);
}
return def;
}
/**
* Determine if name refers to a property
*
* @param defName
* @return
*/
public PropertyDefinition determineProperty(QName defName)
{
PropertyDefinition def = null;
if (nodeProperties.containsKey(defName) == false)
{
def = getDictionaryService().getProperty(typeDef.getName(), defName);
if (def == null)
{
Set<AspectDefinition> allAspects = new HashSet<AspectDefinition>();
allAspects.addAll(typeDef.getDefaultAspects());
allAspects.addAll(nodeAspects.values());
for (AspectDefinition aspectDef : allAspects)
{
def = getDictionaryService().getProperty(aspectDef.getName(), defName);
if (def != null)
{
break;
}
}
}
}
return def;
}
/**
* Determine if name referes to an association
*
* @param defName
* @return
*/
public AssociationDefinition determineAssociation(QName defName)
{
AssociationDefinition def = null;
if (nodeChildAssocs.containsKey(defName) == false)
{
def = getDictionaryService().getAssociation(defName);
}
return def;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return "NodeContext[childName=" + getChildName() + ",type=" + (typeDef == null ? "null" : typeDef.getName()) + ",nodeRef=" + nodeRef +
",aspects=" + nodeAspects.values() + ",parentContext=" + parentContext.toString() + "]";
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer.view;
import org.alfresco.service.namespace.QName;
/**
* Represents Property Context
*
* @author David Caruana
*
*/
public class NodeItemContext extends ElementContext
{
private NodeContext nodeContext;
/**
* Construct
*
* @param elementName
* @param dictionary
* @param importer
*/
public NodeItemContext(QName elementName, NodeContext nodeContext)
{
super(elementName, nodeContext.getDictionaryService(), nodeContext.getImporter());
this.nodeContext = nodeContext;
}
/**
* Gets the Node Context
*/
public NodeContext getNodeContext()
{
return nodeContext;
}
}

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer.view;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.importer.ImportParent;
import org.alfresco.repo.importer.Importer;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
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.namespace.QName;
/**
* Maintains state about the parent context of the node being imported.
*
* @author David Caruana
*
*/
public class ParentContext extends ElementContext
implements ImportParent
{
private NodeRef parentRef;
private QName assocType;
/**
* Construct
*
* @param dictionary
* @param configuration
* @param progress
* @param elementName
* @param parentRef
* @param assocType
*/
public ParentContext(QName elementName, DictionaryService dictionary, Importer importer)
{
super(elementName, dictionary, importer);
parentRef = importer.getRootRef();
assocType = importer.getRootAssocType();
}
/**
* Construct (with unknown child association)
*
* @param elementName
* @param parent
*/
public ParentContext(QName elementName, NodeContext parent)
{
super(elementName, parent.getDictionaryService(), parent.getImporter());
parentRef = parent.getNodeRef();
}
/**
* Construct
*
* @param elementName
* @param parent
* @param childDef
*/
public ParentContext(QName elementName, NodeContext parent, ChildAssociationDefinition childDef)
{
this(elementName, parent);
// Ensure association is valid for node
Set<QName> allAspects = new HashSet<QName>();
for (AspectDefinition typeAspect : parent.getTypeDefinition().getDefaultAspects())
{
allAspects.add(typeAspect.getName());
}
allAspects.addAll(parent.getNodeAspects());
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();
assocType = childDef.getName();
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportParent#getParentRef()
*/
public NodeRef getParentRef()
{
return parentRef;
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.ImportParent#getAssocType()
*/
public QName getAssocType()
{
return assocType;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return "ParentContext[parent=" + parentRef + ",assocType=" + getAssocType() + "]";
}
}

View File

@@ -0,0 +1,634 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.importer.view;
import java.io.IOException;
import java.io.Reader;
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.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.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
/**
* Importer for parsing and importing nodes given the Repository View schema.
*
* @author David Caruana
*/
public class ViewParser implements Parser
{
// Logger
private static final Log logger = LogFactory.getLog(ViewParser.class);
// View schema elements and attributes
private static final String VIEW_CHILD_NAME_ATTR = "childName";
private static final String VIEW_DATATYPE_ATTR = "datatype";
private static final String VIEW_ISNULL_ATTR = "isNull";
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");
private static final QName VIEW_ASPECTS = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "aspects");
private static final QName VIEW_PROPERTIES = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "properties");
private static final QName VIEW_ASSOCIATIONS = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "associations");
// XML Pull Parser Factory
private XmlPullParserFactory factory;
// Supporting services
private NamespaceService namespaceService;
private DictionaryService dictionaryService;
/**
* Construct
*/
public ViewParser()
{
try
{
// Construct Xml Pull Parser Factory
factory = XmlPullParserFactory.newInstance(System.getProperty(XmlPullParserFactory.PROPERTY_NAME), this.getClass());
factory.setNamespaceAware(true);
}
catch (XmlPullParserException e)
{
throw new ImporterException("Failed to initialise view importer", e);
}
}
/**
* @param namespaceService the namespace service
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param dictionaryService the dictionary service
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/* (non-Javadoc)
* @see org.alfresco.repo.importer.Parser#parse(java.io.Reader, org.alfresco.repo.importer.Importer)
*/
public void parse(Reader viewReader, Importer importer)
{
try
{
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(viewReader);
Stack<ElementContext> contextStack = new Stack<ElementContext>();
try
{
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.END_DOCUMENT; eventType = xpp.next())
{
switch (eventType)
{
case XmlPullParser.START_TAG:
{
if (xpp.getDepth() == 1)
{
processRoot(xpp, importer, contextStack);
}
else
{
processStartElement(xpp, contextStack);
}
break;
}
case XmlPullParser.END_TAG:
{
processEndElement(xpp, contextStack);
break;
}
}
}
}
catch(Exception e)
{
throw new ImporterException("Failed to import package at line " + xpp.getLineNumber() + "; column " + xpp.getColumnNumber() + " due to error: " + e.getMessage(), e);
}
}
catch(XmlPullParserException e)
{
throw new ImporterException("Failed to parse view", e);
}
}
/**
* Process start of xml element
*
* @param xpp
* @param contextStack
* @throws XmlPullParserException
* @throws IOException
*/
private void processStartElement(XmlPullParser xpp, Stack<ElementContext> contextStack)
throws XmlPullParserException, IOException
{
// Extract qualified name
QName defName = getName(xpp);
// Process the element
Object context = contextStack.peek();
// Handle special view directives
if (defName.equals(VIEW_METADATA))
{
contextStack.push(new MetaDataContext(defName, (ElementContext)context));
}
else if (defName.equals(VIEW_ASPECTS) || defName.equals(VIEW_PROPERTIES) || defName.equals(VIEW_ASSOCIATIONS))
{
if (context instanceof NodeItemContext)
{
throw new ImporterException("Cannot nest element " + defName + " within " + ((NodeItemContext)context).getElementName());
}
if (!(context instanceof NodeContext))
{
throw new ImporterException("Element " + defName + " can only be declared within a node");
}
NodeContext nodeContext = (NodeContext)context;
contextStack.push(new NodeItemContext(defName, nodeContext));
}
else
{
if (context instanceof MetaDataContext)
{
processMetaData(xpp, defName, contextStack);
}
else if (context instanceof ParentContext)
{
// 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, contextStack);
return;
}
else if (context instanceof NodeContext)
{
// Process children of node
// Note: Process in the following order: aspects, properties and associations
Object def = ((NodeContext)context).determineDefinition(defName);
if (def == null)
{
throw new ImporterException("Definition " + defName + " is not valid; cannot find in Repository dictionary");
}
if (def instanceof AspectDefinition)
{
processAspect(xpp, (AspectDefinition)def, contextStack);
return;
}
else if (def instanceof PropertyDefinition)
{
processProperty(xpp, ((PropertyDefinition)def).getName(), contextStack);
return;
}
else if (def instanceof ChildAssociationDefinition)
{
processStartChildAssoc(xpp, (ChildAssociationDefinition)def, contextStack);
return;
}
else
{
// TODO: general association
}
}
else if (context instanceof NodeItemContext)
{
NodeItemContext nodeItemContext = (NodeItemContext)context;
NodeContext nodeContext = nodeItemContext.getNodeContext();
QName itemName = nodeItemContext.getElementName();
if (itemName.equals(VIEW_ASPECTS))
{
AspectDefinition def = nodeContext.determineAspect(defName);
if (def == null)
{
throw new ImporterException("Aspect name " + defName + " is not valid; cannot find in Repository dictionary");
}
processAspect(xpp, def, contextStack);
}
else if (itemName.equals(VIEW_PROPERTIES))
{
// Note: Allow properties which do not have a data dictionary definition
processProperty(xpp, defName, contextStack);
}
else if (itemName.equals(VIEW_ASSOCIATIONS))
{
// TODO: Handle general associations...
ChildAssociationDefinition def = (ChildAssociationDefinition)nodeContext.determineAssociation(defName);
if (def == null)
{
throw new ImporterException("Association name " + defName + " is not valid; cannot find in Repository dictionary");
}
processStartChildAssoc(xpp, def, contextStack);
}
}
}
}
/**
* Process Root
*
* @param xpp
* @param parentRef
* @param childAssocType
* @param configuration
* @param progress
* @param contextStack
* @throws XmlPullParserException
* @throws IOException
*/
private void processRoot(XmlPullParser xpp, Importer importer, Stack<ElementContext> contextStack)
throws XmlPullParserException, IOException
{
ParentContext parentContext = new ParentContext(getName(xpp), dictionaryService, importer);
contextStack.push(parentContext);
if (logger.isDebugEnabled())
logger.debug(indentLog("Pushed " + parentContext, contextStack.size() -1));
}
/**
* Process meta-data
*
* @param xpp
* @param metaDataName
* @param contextStack
* @throws XmlPullParserException
* @throws IOException
*/
private void processMetaData(XmlPullParser xpp, QName metaDataName, Stack<ElementContext> contextStack)
throws XmlPullParserException, IOException
{
MetaDataContext context = (MetaDataContext)contextStack.peek();
String value = null;
int eventType = xpp.next();
if (eventType == XmlPullParser.TEXT)
{
// Extract value
value = xpp.getText();
eventType = xpp.next();
}
if (eventType != XmlPullParser.END_TAG)
{
throw new ImporterException("Meta data element " + metaDataName + " is missing end tag");
}
context.setProperty(metaDataName, value);
}
/**
* Process start of a node definition
*
* @param xpp
* @param typeDef
* @param contextStack
* @throws XmlPullParserException
* @throws IOException
*/
private void processStartType(XmlPullParser xpp, TypeDefinition typeDef, Stack<ElementContext> contextStack)
throws XmlPullParserException, IOException
{
ParentContext parentContext = (ParentContext)contextStack.peek();
NodeContext context = new NodeContext(typeDef.getName(), parentContext, 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);
}
contextStack.push(context);
if (logger.isDebugEnabled())
logger.debug(indentLog("Pushed " + context, contextStack.size() -1));
}
/**
* Process aspect definition
*
* @param xpp
* @param aspectDef
* @param contextStack
* @throws XmlPullParserException
* @throws IOException
*/
private void processAspect(XmlPullParser xpp, AspectDefinition aspectDef, Stack<ElementContext> contextStack)
throws XmlPullParserException, IOException
{
NodeContext context = peekNodeContext(contextStack);
context.addAspect(aspectDef);
int eventType = xpp.next();
if (eventType != XmlPullParser.END_TAG)
{
throw new ImporterException("Aspect " + aspectDef.getName() + " definition is not valid - it cannot contain any elements");
}
if (logger.isDebugEnabled())
logger.debug(indentLog("Processed aspect " + aspectDef.getName(), contextStack.size()));
}
/**
* Process property definition
*
* @param xpp
* @param propDef
* @param contextStack
* @throws XmlPullParserException
* @throws IOException
*/
private void processProperty(XmlPullParser xpp, QName propertyName, Stack<ElementContext> contextStack)
throws XmlPullParserException, IOException
{
NodeContext context = peekNodeContext(contextStack);
// Extract single value
String value = "";
int eventType = xpp.next();
if (eventType == XmlPullParser.TEXT)
{
value = xpp.getText();
eventType = xpp.next();
}
if (eventType == XmlPullParser.END_TAG)
{
context.addProperty(propertyName, value);
}
else
{
// Extract collection, if specified
boolean isCollection = false;
if (eventType == XmlPullParser.START_TAG)
{
QName name = getName(xpp);
if (name.equals(VIEW_VALUES_QNAME))
{
context.addPropertyCollection(propertyName);
isCollection = true;
eventType = xpp.next();
if (eventType == XmlPullParser.TEXT)
{
eventType = xpp.next();
}
}
}
// Extract decorated value
while (eventType == XmlPullParser.START_TAG)
{
QName name = getName(xpp);
if (!name.equals(VIEW_VALUE_QNAME))
{
throw new ImporterException("Invalid view structure - expected element " + VIEW_VALUE_QNAME + " for property " + propertyName);
}
QName datatype = QName.createQName(xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_DATATYPE_ATTR), namespaceService);
Boolean isNull = Boolean.valueOf(xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_ISNULL_ATTR));
String decoratedValue = isNull ? null : "";
eventType = xpp.next();
if (eventType == XmlPullParser.TEXT)
{
decoratedValue = xpp.getText();
eventType = xpp.next();
}
if (eventType == XmlPullParser.END_TAG)
{
context.addProperty(propertyName, decoratedValue);
if (datatype != null)
{
context.addDatatype(propertyName, dictionaryService.getDataType(datatype));
}
}
else
{
throw new ImporterException("Value for property " + propertyName + " has not been defined correctly - missing end tag");
}
eventType = xpp.next();
if (eventType == XmlPullParser.TEXT)
{
eventType = xpp.next();
}
}
// End of value
if (eventType != XmlPullParser.END_TAG)
{
throw new ImporterException("Invalid view structure - property " + propertyName + " definition is invalid");
}
// End of collection
if (isCollection)
{
eventType = xpp.next();
if (eventType == XmlPullParser.TEXT)
{
eventType = xpp.next();
}
if (eventType != XmlPullParser.END_TAG)
{
throw new ImporterException("Invalid view structure - property " + propertyName + " definition is invalid");
}
}
}
if (logger.isDebugEnabled())
logger.debug(indentLog("Processed property " + propertyName, contextStack.size()));
}
/**
* Process start of child association definition
*
* @param xpp
* @param childAssocDef
* @param contextStack
* @throws XmlPullParserException
* @throws IOException
*/
private void processStartChildAssoc(XmlPullParser xpp, ChildAssociationDefinition childAssocDef, Stack<ElementContext> contextStack)
throws XmlPullParserException, IOException
{
NodeContext context = peekNodeContext(contextStack);
if (context.getNodeRef() == null)
{
// Create Node
NodeRef nodeRef = context.getImporter().importNode(context);
context.setNodeRef(nodeRef);
}
// Construct Child Association Context
ParentContext parentContext = new ParentContext(childAssocDef.getName(), context, childAssocDef);
contextStack.push(parentContext);
if (logger.isDebugEnabled())
logger.debug(indentLog("Pushed " + parentContext, contextStack.size() -1));
}
/**
* Process end of xml element
*
* @param xpp
* @param contextStack
*/
private void processEndElement(XmlPullParser xpp, Stack<ElementContext> contextStack)
{
ElementContext context = contextStack.peek();
if (context.getElementName().getLocalName().equals(xpp.getName()) &&
context.getElementName().getNamespaceURI().equals(xpp.getNamespace()))
{
context = contextStack.pop();
if (logger.isDebugEnabled())
logger.debug(indentLog("Popped " + context, contextStack.size()));
if (context instanceof NodeContext)
{
processEndType((NodeContext)context);
}
else if (context instanceof ParentContext)
{
processEndChildAssoc((ParentContext)context);
}
else if (context instanceof MetaDataContext)
{
processEndMetaData((MetaDataContext)context);
}
}
}
/**
* Process end of the type definition
*
* @param context
*/
private void processEndType(NodeContext context)
{
NodeRef nodeRef = context.getNodeRef();
if (nodeRef == null)
{
nodeRef = context.getImporter().importNode(context);
context.setNodeRef(nodeRef);
}
context.getImporter().childrenImported(nodeRef);
}
/**
* Process end of the child association
*
* @param context
*/
private void processEndChildAssoc(ParentContext context)
{
}
/**
* Process end of meta data
*
* @param context
*/
private void processEndMetaData(MetaDataContext context)
{
context.getImporter().importMetaData(context.getProperties());
}
/**
* Get parent Node Context
*
* @param contextStack context stack
* @return node context
*/
private NodeContext peekNodeContext(Stack<ElementContext> contextStack)
{
ElementContext context = contextStack.peek();
if (context instanceof NodeContext)
{
return (NodeContext)context;
}
else if (context instanceof NodeItemContext)
{
return ((NodeItemContext)context).getNodeContext();
}
throw new ImporterException("Internal error: Failed to retrieve node context");
}
/**
* Helper to create Qualified name from current xml element
*
* @param xpp
* @return
*/
private QName getName(XmlPullParser xpp)
{
// Ensure namespace is valid
String uri = xpp.getNamespace();
if (namespaceService.getURIs().contains(uri) == false)
{
throw new ImporterException("Namespace URI " + uri + " has not been defined in the Repository dictionary");
}
// Construct name
String name = xpp.getName();
return QName.createQName(uri, name);
}
/**
* Helper to indent debug output
*
* @param msg
* @param depth
* @return
*/
private String indentLog(String msg, int depth)
{
StringBuffer buf = new StringBuffer(1024);
for (int i = 0; i < depth; i++)
{
buf.append(' ');
}
buf.append(msg);
return buf.toString();
}
}