Skip to content

Commit

Permalink
fix: Update OO to 8.2 - EXO-74305
Browse files Browse the repository at this point in the history
Add Upgrade plugin for convert OO documents from oform and docxf to pdf for OO 8.2
  • Loading branch information
rdenarie committed Jan 8, 2025
1 parent 3ca83f7 commit 728d1cb
Show file tree
Hide file tree
Showing 5 changed files with 374 additions and 0 deletions.
4 changes: 4 additions & 0 deletions data-upgrade-packaging/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
<groupId>${project.groupId}</groupId>
<artifactId>data-upgrade-move-folders</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>data-upgrade-processes-documents</artifactId>
</dependency>
</dependencies>
<build>
<finalName>data-upgrade-addon</finalName>
Expand Down
36 changes: 36 additions & 0 deletions data-upgrade-processes-documents/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.exoplatform.addons.upgrade</groupId>
<artifactId>upgrade</artifactId>
<version>7.0.x-SNAPSHOT</version>
</parent>

<artifactId>data-upgrade-processes-documents</artifactId>
<packaging>jar</packaging>
<name>eXo Add-on:: Data Upgrade Add-on - Processes Document</name>
<description>Update oform and docxf document to pdf</description>
<dependencies>
<dependency>
<groupId>io.meeds.social</groupId>
<artifactId>social-component-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.exoplatform.jcr</groupId>
<artifactId>exo.jcr.component.ext</artifactId>
</dependency>
<dependency>
<groupId>org.exoplatform.addons.onlyoffice</groupId>
<artifactId>exo-onlyoffice-editor-services</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>

<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
package org.exoplatform.migration;

import jakarta.persistence.EntityManager;
import org.exoplatform.commons.persistence.impl.EntityManagerService;
import org.exoplatform.commons.upgrade.UpgradePluginExecutionContext;
import org.exoplatform.commons.upgrade.UpgradeProductPlugin;
import org.exoplatform.container.component.RequestLifeCycle;
import org.exoplatform.onlyoffice.OnlyofficeEditorService;
import org.exoplatform.portal.config.UserACL;
import org.exoplatform.services.attachments.model.AttachmentContextEntity;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
import org.exoplatform.services.jcr.impl.core.NodeImpl;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.container.xml.InitParams;

import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ProcessesDocumentsUpgradePlugin extends UpgradeProductPlugin {
private static final Log log = ExoLogger.getExoLogger(ProcessesDocumentsUpgradePlugin.class);

private RepositoryService repositoryService;
private OnlyofficeEditorService onlyofficeEditorService;
private EntityManagerService entityManagerService;
private UserACL userACL;

public ProcessesDocumentsUpgradePlugin(EntityManagerService entityManagerService, RepositoryService repositoryService, OnlyofficeEditorService onlyofficeEditorService, UserACL userACL, InitParams initParams) {
super(initParams);
this.repositoryService = repositoryService;
this.onlyofficeEditorService = onlyofficeEditorService;
this.userACL = userACL;
this.entityManagerService = entityManagerService;
}

@Override
public void processUpgrade(String oldVersion, String newVersion) {
long startupTime = System.currentTimeMillis();
log.info("Start Processes documents upgrade");

List<String> errorPath = new ArrayList<>();

try {


List<AttachmentContextEntity> attachments = getAllAttachments();

SessionProvider sessionProvider = SessionProvider.createSystemProvider();
Session session = sessionProvider.getSession("collaboration", repositoryService.getDefaultRepository());

Map<String,String> attachmentIdReplacement = new HashMap<>();

long total = attachments.size();
int currentIndex=0;
log.info("Processes documents upgrade Select query executed in {} ms, {} elements to check", System.currentTimeMillis()-startupTime, total);

for (AttachmentContextEntity attachment : attachments) {
if (!attachmentIdReplacement.containsKey(attachment.getAttachmentId())) {

try {
Node file = session.getNodeByUUID(attachment.getAttachmentId());


log.debug("Proceed node {}", file.getPath());

if (!file.getPath().startsWith("/Trash") && file.isNodeType("nt:file") && (file.getName().endsWith(".docxf")
|| file.getName().endsWith(".oform"))) {
byte[] convertedContent;
String owner = userACL.getSuperUser();
convertedContent = this.onlyofficeEditorService.convertNodeContentToPdf(file, owner);
if (convertedContent != null) {
String newFileUuid = createNewFile(convertedContent, file);
attachmentIdReplacement.put(attachment.getAttachmentId(), newFileUuid);
} else {
errorPath.add(file.getPath());
}

}
} catch(ItemNotFoundException e) {
log.warn("Node with uuid {} not exists in collaboration workspace", attachment.getAttachmentId());
} catch (UnsupportedRepositoryOperationException e) {
log.warn("Node with uuid {} cannot be read (must be a symlink, ignore it)", attachment.getAttachmentId());
} catch (ItemExistsException e) {
log.warn("Node with uuid {} already converted", attachment.getAttachmentId());
}
}
currentIndex++;
if (currentIndex % 100 == 0) {
log.info("{}/{} elements processed", currentIndex, total);
}
}

log.info("{} documents converted. Start step 2 to update attachment table", attachmentIdReplacement.size());

attachmentIdReplacement.forEach(this::updateAttachementUuId);

if (!errorPath.isEmpty()) {
throw new IllegalStateException(String.format("End converting documents. %s documents converted. There are %s errors for files %s. It took %s ms.",
attachmentIdReplacement.size(),
errorPath.size(),
errorPath,
(System.currentTimeMillis() - startupTime)));
} else {
log.info("End Processes documents upgrade, execution time={}ms, {} elements processed, {} converted",
System.currentTimeMillis() - startupTime,
total,
attachmentIdReplacement.size());
}
} catch (Exception e) {
log.error("Error when updating document for OO 8",e);
throw new IllegalStateException("Upgrade Plugin not executed");
}
}

private String createNewFile(byte[] convertedContent, Node file) throws Exception {
log.debug("File converted in a byte array of lenght={}", convertedContent.length);
Node newNode = duplicateItem(file, file.getParent(), file.getParent());
Node jcrContent = newNode.getNode("jcr:content");
InputStream stream = new ByteArrayInputStream(convertedContent);
jcrContent.setProperty("jcr:mimeType","application/pdf");
jcrContent.setProperty("jcr:data", stream);
file.getParent().save();
return newNode.getUUID();
}

public boolean shouldProceedToUpgrade(String newVersion, String previousGroupVersion, UpgradePluginExecutionContext previousUpgradePluginExecution) {
int executionCount = previousUpgradePluginExecution == null ? 0 : previousUpgradePluginExecution.getExecutionCount();
return !isExecuteOnlyOnce() || executionCount == 0;
}

private List<AttachmentContextEntity> getEntityAttached(String uuid) {
RequestLifeCycle.begin(this.entityManagerService);
EntityManager entityManager = this.entityManagerService.getEntityManager();
List<AttachmentContextEntity> results = new ArrayList<>();
try {
String sqlString = "SELECT * FROM EXO_ATTACHMENTS_CONTEXT WHERE ATTACHMENT_ID = '"+uuid+"'";
jakarta.persistence.Query query = entityManager.createNativeQuery(sqlString, AttachmentContextEntity.class);
results = query.getResultList();
} catch (Exception e) {
log.error("Error when reading attachment entity for file with id={}", uuid,e);
} finally {
RequestLifeCycle.end();
}
return results;
}

private List<AttachmentContextEntity> getAllAttachments() {
RequestLifeCycle.begin(this.entityManagerService);
EntityManager entityManager = this.entityManagerService.getEntityManager();
List<AttachmentContextEntity> results = new ArrayList<>();
try {
String sqlString = "SELECT * FROM EXO_ATTACHMENTS_CONTEXT";
jakarta.persistence.Query query = entityManager.createNativeQuery(sqlString, AttachmentContextEntity.class);
results = query.getResultList();
} catch (Exception e) {
log.error("Error when reading all attachments entity",e);
} finally {
RequestLifeCycle.end();
}
return results;
}

private void updateAttachementUuId(String oldUUID, String newUUID) {
RequestLifeCycle.begin(this.entityManagerService);
EntityManager entityManager = this.entityManagerService.getEntityManager();
try {
entityManager.getTransaction().begin();
String sqlString = "UPDATE EXO_ATTACHMENTS_CONTEXT SET ATTACHMENT_ID = '"+newUUID+"' WHERE ATTACHMENT_ID='"+oldUUID+"'";
jakarta.persistence.Query query = entityManager.createNativeQuery(sqlString, AttachmentContextEntity.class);
query.executeUpdate();
entityManager.getTransaction().commit();
} catch (Exception e) {
log.error("Error when updating attachment for attachmentContext with uuid={}", oldUUID,e);
} finally {
RequestLifeCycle.end();
}
}


private Node duplicateItem(Node oldNode, Node destinationNode, Node parentNode) throws Exception{
Node newNode;
String name = oldNode.getName();
String title = oldNode.getProperty("exo:title").getString();
if (((NodeImpl) destinationNode).getIdentifier().equals(((NodeImpl) parentNode).getIdentifier())){
name = name.replace(".docxf", ".pdf");
name = name.replace(".oform", ".pdf");
title = title.replace(".docxf", ".pdf");
title = title.replace(".oform", ".pdf");
String newName = name;
int i =0;
while((destinationNode.hasNode(newName))){
i++;
newName = name + " (" + i + ")";
}
name = newName.toLowerCase();
if(i>0){
title = title + " (" + i + ")";
}
}
name = URLDecoder.decode(name, "UTF-8");
newNode = destinationNode.addNode(name, oldNode.getPrimaryNodeType().getName());
addProperties(oldNode,newNode,title);
return newNode;
}

private void addProperties(Node oldNode, Node newNode, String title) throws RepositoryException {
if (oldNode.isNodeType("mix:versionable") && !newNode.isNodeType("mix:versionable"))
newNode.addMixin("mix:versionable");

if (oldNode.isNodeType("mix:referenceable") && !newNode.isNodeType("mix:referenceable"))
newNode.addMixin("mix:referenceable");

if (oldNode.isNodeType("mix:commentable") && !newNode.isNodeType("mix:commentable"))
newNode.addMixin("mix:commentable");

if (oldNode.isNodeType("mix:votable") && !newNode.isNodeType("mix:votable"))
newNode.addMixin("mix:votable");

if (oldNode.isNodeType("mix:i18n") && !newNode.isNodeType("mix:i18n"))
newNode.addMixin("mix:i18n");

newNode.setProperty("exo:title", title);
newNode.setProperty("exo:lastModifier",oldNode.getProperty("exo:lastModifier").getString());
newNode.setProperty("exo:dateCreated", oldNode.getProperty("exo:dateCreated").getDate());
newNode.setProperty("exo:dateModified", oldNode.getProperty("exo:dateModified").getDate());
newNode.setProperty("exo:lastModifiedDate", oldNode.getProperty("exo:lastModifiedDate").getDate());
if(oldNode.hasNode("jcr:content")){
Node resourceNode = newNode.addNode("jcr:content", "nt:resource");
resourceNode.setProperty("jcr:data",
oldNode.getNode("jcr:content")
.getProperty("jcr:data")
.getStream());
resourceNode.setProperty("jcr:mimeType",
oldNode.getNode("jcr:content")
.getProperty("jcr:mimeType")
.getString());
resourceNode.setProperty("jcr:lastModified", oldNode.getNode("jcr:content").getProperty("jcr:lastModified").getDate());
resourceNode.setProperty("exo:dateModified", oldNode.getNode("jcr:content").getProperty("exo:dateModified").getDate());
resourceNode.setProperty("exo:dateCreated", oldNode.getNode("jcr:content").getProperty("exo:dateCreated").getDate());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Copyright (C) 2003-2021 eXo Platform SAS.
This is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.
This software 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 software; if not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_3.xsd http://www.exoplatform.org/xml/ns/kernel_1_3.xsd" xmlns="http://www.exoplatform.org/xml/ns/kernel_1_3.xsd">

<external-component-plugins>
<target-component>org.exoplatform.commons.upgrade.UpgradeProductService</target-component>
<component-plugin profiles="processes">
<name>DocumentsProcessesPlugin</name>
<set-method>addUpgradePlugin</set-method>
<type>org.exoplatform.migration.ProcessesDocumentsUpgradePlugin</type>
<description>upgrade documents in processes for OO 8.2</description>
<init-params>
<value-param>
<name>product.group.id</name>
<description>The groupId of the product</description>
<value>org.exoplatform.platform</value>
</value-param>
<value-param>
<name>plugin.upgrade.target.version</name>
<description>The plugin target version of selected groupId</description>
<value>7.0.0</value>
</value-param>
<value-param>
<name>plugin.execution.order</name>
<description>The plugin execution order</description>
<value>10</value>
</value-param>
<value-param>
<name>plugin.upgrade.execute.once</name>
<description>The plugin must be executed only once</description>
<value>true</value>
</value-param>
<value-param>
<name>plugin.upgrade.async.execution</name>
<description>The plugin will be executed in an asynchronous mode</description>
<value>true</value>
</value-param>
</init-params>
</component-plugin>
</external-component-plugins>
</configuration>
Loading

0 comments on commit 728d1cb

Please sign in to comment.