/*
* Copyright (C) 2008-2012 Open Wide SA
*
* This library is free software; you can redistribute
* it and/or modify it under the terms of version 2.1 of
* the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*
* More information at http://knowledge.openwide.fr/bin/view/Main/AlfrescoETLConnector/
*/
package fr.openwide.talendalfresco.acpxml;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import fr.openwide.talendalfresco.importer.ContentImporterConfiguration;
/**
* Content import driver that writes namepath'd documents as ACP XML.
*
* @author Marc Dutoo - Open Wide SA
*
*/
public class TalendAcpXmlWriter {
/** TODO send to server ; TODO or talend param ? */
protected static final String PATH_DELIMITER = File.separator;
/** or in file ? */
protected ByteArrayOutputStream acpXmlBos = new ByteArrayOutputStream();
protected AcpXmlWriter acpXmlWriter = null;
protected List<Map<String,String>> mappedContentNamespaces = null;
/** NB. default to work with tomcat is ISO-8859-1 */
protected String restEncoding;
protected ArrayListStack<String> currentPathNameStack = new ArrayListStack<String>();
/** Set in writeStartContent, unset in end, required in startPrimaryAssociation */
//protected String currentPathName = null;
protected String alfrescoType = "cm:content";
protected List<String> alfrescoAspects = null;
protected String containerType = "cm:folder";
protected String containerChildAssociationType = "cm:contains";
protected boolean configurePermission = false;
protected boolean permissionOnDocumentAndNotContainer = false;
protected boolean inheritPermissions = true;
//protected List<Map<String,String>> permissions = null;
public TalendAcpXmlWriter() {
}
public void start() throws AcpXmlException {
this.acpXmlWriter = new AcpXmlWriter(acpXmlBos, restEncoding, mappedContentNamespaces);
}
public void writeNamespace(String contentNsPrefix, String contentNsUri) throws AcpXmlException {
acpXmlWriter.writeNamespace(contentNsPrefix, contentNsUri);
}
/**
* Moves to target location (from last writeEndDocument),
* then writes type, permissions, aspects.
* Out of this method remains to be done for this document :
* properties
* associations
* end document
* TODO even same with [][] ??
* @param targetLocation
* @param permissionValues
* @throws AcpXmlException
*/
public void writeStartDocument(String targetLocation,
String[][] permissionValues) throws AcpXmlException {
moveToTargetLocation(targetLocation, permissionValues);
acpXmlWriter.writeStartContent(alfrescoType, ContentImporterConfiguration.CHILD_NAME_DOCUMENT);
if (configurePermission && permissionOnDocumentAndNotContainer) {
writeStartPermissions();
for (String[] permissionValue : permissionValues) {
String authority = permissionValue[0];
String permission = permissionValue[1];
acpXmlWriter.writePermission(authority, permission);
}
writeEndPermissions();
}
writeDocumentAspects();
}
public void close() throws AcpXmlException {
while (!currentPathNameStack.isEmpty()) {
currentPathNameStack.pop();
writeEndContainer();
}
acpXmlWriter.close();
}
public String toString() {
return acpXmlBos.toString();
}
/**
* Moves to target location (from last writeEndDocument)
* @param targetLocation
* @param permissionValues full permission info requried
* @throws AcpXmlException
*/
protected void moveToTargetLocation(String targetLocation,
String[][] permissionValues) throws AcpXmlException {
ArrayList<String> pathNames = AcpXmlUtil.stringToNamePath(targetLocation, PATH_DELIMITER);
// 1. getting last same pathName index
int firstDifferentPathNameIndex = 0;
int pathNameNb = pathNames.size();
int currentPathNameStackSize = currentPathNameStack.size();
for (; firstDifferentPathNameIndex < pathNameNb
&& firstDifferentPathNameIndex < currentPathNameStackSize; firstDifferentPathNameIndex++) {
String pathName = pathNames.get(firstDifferentPathNameIndex);
if (!currentPathNameStack.get(firstDifferentPathNameIndex).equals(pathName)) {
// found firstDifferentPathNameIndex !
break;
}
}
// 2. unstacking (and ending containers) until last same path name
for (int i = currentPathNameStackSize - 1; i >= firstDifferentPathNameIndex; i--) {
currentPathNameStack.pop();
writeEndContainer();
}
//3. stacking remaining target location pathNames (and starting containers)
// if any, stack them up
if (firstDifferentPathNameIndex != pathNameNb) {
// stack all of them but the last one
for (int i = firstDifferentPathNameIndex; i < pathNameNb - 1; i++) {
String remainingPathName = pathNames.get(i);
writeStartContainer(remainingPathName);
currentPathNameStack.push(remainingPathName);
}
// now write last container and companion permissions if any :
String lastPathName = pathNames.get(pathNameNb - 1);
writeStartLastContainer(lastPathName, permissionValues);
currentPathNameStack.push(lastPathName);
}
}
protected void writeStartContainer(String name) throws AcpXmlException {
acpXmlWriter.writeStartContent(containerType, ContentImporterConfiguration.CHILD_NAME_CONTAINER);
// no custom permissions
writeContainerUntilChildren(name);
}
protected void writeStartLastContainer(String name, String[][] permissionValues) throws AcpXmlException {
acpXmlWriter.writeStartContent(containerType, ContentImporterConfiguration.CHILD_NAME_CONTAINER);
if (configurePermission && !permissionOnDocumentAndNotContainer) {
writeStartPermissions();
for (String[] permissionValue : permissionValues) {
String authority = permissionValue[0];
String permission = permissionValue[1];
acpXmlWriter.writePermission(authority, permission);
}
writeEndPermissions();
}
writeContainerUntilChildren(name);
}
protected void writeContainerUntilChildren(String name) throws AcpXmlException {
// no additional aspects
acpXmlWriter.writeStartProperties();
acpXmlWriter.writeProperty("cm:name", "d:text", name);
acpXmlWriter.writeEndProperties();
// no other properties
// starting containment child asso
acpXmlWriter.writeStartAssociations();
acpXmlWriter.writeStartPrimaryChildAssociation(containerChildAssociationType);
}
////////////////////////
// bare methods
public void writeStartPermissions() throws AcpXmlException {
acpXmlWriter.writeStartPermissions(inheritPermissions);
}
public void writePermission(Map<String, String> permissionMapping,
Object optUserOrGroupColumnValue) throws AcpXmlException {
acpXmlWriter.writePermission(permissionMapping, optUserOrGroupColumnValue);
}
public void writeEndPermissions() throws AcpXmlException {
acpXmlWriter.writeEndPermissions();
}
public void writeDocumentAspects() throws AcpXmlException{
acpXmlWriter.writeAspects(alfrescoAspects);
}
public void writeStartProperties() throws AcpXmlException {
acpXmlWriter.writeStartProperties();
}
/**
* Must be between writeStartProperties() & writeEndProperties() in a document
* @param propertyMappings prefixed alfresco property ; mapped
* NAME, TITLE (not used), TYPE (used for conversion ?? TODO),
* MANDATORY (could be used for check ?), DEFAULT (not used ?),
* COLUMN (not used), VALUE (here is talend-side default if any)
* @param value list if multiple, else toString() serializes it ;
* if null takes talend-side default (VALUE)
* @throws AcpXmlException
*/
public void writeMappedProperty(Map<String, String> propertyMapping,
Object value) throws AcpXmlException {
acpXmlWriter.writeMappedProperty(propertyMapping, value);
}
/**
* Must be between writeStartProperties() & writeEndProperties() in a document
* @param propertyName
* @param propertyType
* @param value
* @throws AcpXmlException
*/
public void writeProperty(String propertyName, String propertyType,
Object value) throws AcpXmlException {
acpXmlWriter.writeProperty(propertyName, propertyType, value);
}
public void writeEndProperties() throws AcpXmlException {
acpXmlWriter.writeEndProperties();
}
public void writeStartAssociations() throws AcpXmlException {
acpXmlWriter.writeStartAssociations();
}
/**
* Must be between writeStartAssociations() & writeEndAssociations() in a document
* @param associationMappings prefixed alfresco (non primary child) associations ; list of mapped
* NAME, CHILD (not used), TITLE (not used), TYPE (used for conversion ?? TODO),
* MANDATORY (could be used for check ?), MANY (not used),
* COLUMN (not used), new ! VALUE (here should be runtime found namepath ref TODO or other param ?)
* @param ref if List, multiple TODO ? else anything that the server importer binding can understand
* (in alfresco talend, namepathref is OK TODO)
* @throws AcpXmlException
*/
public void writeMappedAssociation(Map<String, String> associationMappings,
Object ref) throws AcpXmlException{
acpXmlWriter.writeMappedAssociation(associationMappings, ref);
}
/**
* Must be between writeStartAssociations() & writeEndAssociations() in a document
* @param associationName
* @param ref
* @throws AcpXmlException
*/
public void writeAssociation(String associationName,
Object ref) throws AcpXmlException{
acpXmlWriter.writeAssociation(associationName, ref);
}
public void writeEndAssociations() throws AcpXmlException {
acpXmlWriter.writeEndAssociations();
}
public void writeEndDocument() throws AcpXmlException {
acpXmlWriter.writeEndContent();
}
public void writeEndContainer() throws AcpXmlException {
acpXmlWriter.writeEndPrimaryChildAssociation(); // end cm:contains
acpXmlWriter.writeEndAssociations(); // end view:associations
acpXmlWriter.writeEndContent(); // end cm:content
}
public void setMappedContentNamespaces(List<Map<String, String>> mappedContentNamespaces) {
this.mappedContentNamespaces = mappedContentNamespaces;
}
public String getAlfrescoType() {
return alfrescoType;
}
public void setAlfrescoType(String alfrescoType) {
this.alfrescoType = alfrescoType;
}
public void setMappedAlfrescoAspects(List<Map<String, String>> mappedAlfrescoAspects) {
if (mappedAlfrescoAspects != null) {
this.alfrescoAspects = new ArrayList<String>(mappedAlfrescoAspects.size());
for (Map<String,String> mappedAlfrescoAspect : mappedAlfrescoAspects) {
String alfrescoAspectName = mappedAlfrescoAspect.get("NAME");
this.alfrescoAspects.add(alfrescoAspectName); // "app:uifacets"
}
}
}
public void setAlfrescoAspects(List<String> alfrescoAspects) {
this.alfrescoAspects = alfrescoAspects;
}
public String getContainerType() {
return containerType;
}
public void setContainerType(String containerType) {
this.containerType = containerType;
}
public String getContainerChildAssociationType() {
return containerChildAssociationType;
}
public void setContainerChildAssociationType(
String containerChildAssociationType) {
this.containerChildAssociationType = containerChildAssociationType;
}
public boolean isConfigurePermission() {
return configurePermission;
}
public void setConfigurePermission(boolean configurePermission) {
this.configurePermission = configurePermission;
}
public boolean isPermissionOnDocumentAndNotContainer() {
return permissionOnDocumentAndNotContainer;
}
public void setPermissionOnDocumentAndNotContainer(
boolean permissionOnDocumentAndNotContainer) {
this.permissionOnDocumentAndNotContainer = permissionOnDocumentAndNotContainer;
}
public boolean isInheritPermissions() {
return inheritPermissions;
}
public void setInheritPermissions(boolean inheritPermissions) {
this.inheritPermissions = inheritPermissions;
}
public String getRestEncoding() {
return restEncoding;
}
public void setRestEncoding(String restEncoding) {
this.restEncoding = restEncoding;
}
/*public List<Map<String, String>> getPermissions() {
return permissions;
}
public void setPermissions(List<Map<String, String>> permissions) {
this.permissions = permissions;
}*/
}