001/* 002 * (C) Copyright 2018 Nuxeo (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Funsho David 018 */ 019 020package org.nuxeo.ecm.core.bulk.action; 021 022import static org.nuxeo.ecm.core.api.event.CoreEventConstants.REPOSITORY_NAME; 023import static org.nuxeo.ecm.core.api.event.CoreEventConstants.SESSION_ID; 024import static org.nuxeo.ecm.core.api.event.DocumentEventCategories.EVENT_DOCUMENT_CATEGORY; 025import static org.nuxeo.ecm.core.api.trash.TrashService.DOCUMENT_TRASHED; 026import static org.nuxeo.ecm.core.api.trash.TrashService.DOCUMENT_UNTRASHED; 027import static org.nuxeo.ecm.core.bulk.BulkServiceImpl.STATUS_STREAM; 028import static org.nuxeo.lib.stream.computation.AbstractComputation.INPUT_1; 029import static org.nuxeo.lib.stream.computation.AbstractComputation.OUTPUT_1; 030 031import java.io.Serializable; 032import java.util.ArrayList; 033import java.util.Arrays; 034import java.util.Collection; 035import java.util.HashSet; 036import java.util.List; 037import java.util.Map; 038import java.util.Set; 039 040import org.apache.logging.log4j.LogManager; 041import org.apache.logging.log4j.Logger; 042import org.nuxeo.ecm.core.api.CoreSession; 043import org.nuxeo.ecm.core.api.DocumentModelList; 044import org.nuxeo.ecm.core.api.DocumentRef; 045import org.nuxeo.ecm.core.api.IdRef; 046import org.nuxeo.ecm.core.api.IterableQueryResult; 047import org.nuxeo.ecm.core.api.NuxeoException; 048import org.nuxeo.ecm.core.api.PropertyException; 049import org.nuxeo.ecm.core.bulk.action.computation.AbstractBulkComputation; 050import org.nuxeo.ecm.core.event.Event; 051import org.nuxeo.ecm.core.event.EventService; 052import org.nuxeo.ecm.core.event.impl.DocumentEventContext; 053import org.nuxeo.ecm.core.query.sql.NXQL; 054import org.nuxeo.lib.stream.computation.Topology; 055import org.nuxeo.runtime.api.Framework; 056import org.nuxeo.runtime.stream.StreamProcessorTopology; 057 058/** 059 * @since 10.3 060 */ 061public class TrashAction implements StreamProcessorTopology { 062 063 public static final String ACTION_NAME = "trash"; 064 065 public static final String PARAM_NAME = "value"; 066 067 public static final String PROXY_QUERY_TEMPLATE = "SELECT ecm:uuid FROM Document WHERE ecm:isProxy=1 AND ecm:uuid IN ('%s')"; 068 069 public static final String SYSPROP_QUERY_TEMPLATE = "SELECT ecm:uuid FROM Document WHERE ecm:isProxy=0 AND ecm:isTrashed=%s AND ecm:uuid IN ('%s')"; 070 071 @Override 072 public Topology getTopology(Map<String, String> options) { 073 return Topology.builder() 074 .addComputation(TrashComputation::new, 075 Arrays.asList(INPUT_1 + ":" + ACTION_NAME, OUTPUT_1 + ":" + STATUS_STREAM)) 076 .build(); 077 } 078 079 public static class TrashComputation extends AbstractBulkComputation { 080 081 private static final Logger log = LogManager.getLogger(TrashComputation.class); 082 083 public TrashComputation() { 084 super(ACTION_NAME); 085 } 086 087 @Override 088 protected void compute(CoreSession session, List<String> ids, Map<String, Serializable> properties) { 089 Boolean trashValue = (Boolean) properties.get(PARAM_NAME); 090 if (trashValue) { 091 removeProxies(session, ids); 092 } 093 setSystemProperty(session, ids, trashValue); 094 } 095 096 protected void removeProxies(CoreSession session, List<String> ids) { 097 Set<DocumentRef> proxies = new HashSet<>(); 098 String query = String.format(PROXY_QUERY_TEMPLATE, String.join("', '", ids)); 099 try (IterableQueryResult res = session.queryAndFetch(query, NXQL.NXQL)) { 100 for (Map<String, Serializable> map : res) { 101 proxies.add(new IdRef((String) map.get(NXQL.ECM_UUID))); 102 } 103 } 104 session.removeDocuments(proxies.toArray(new DocumentRef[0])); 105 try { 106 session.save(); 107 } catch (PropertyException e) { 108 // TODO send to error stream 109 log.warn("Cannot save session", e); 110 } 111 } 112 113 public void setSystemProperty(CoreSession session, List<String> ids, Boolean value) { 114 List<DocumentRef> updatedRefs = new ArrayList<>(ids.size()); 115 String query = String.format(SYSPROP_QUERY_TEMPLATE, value ? "0" : "1", String.join("', '", ids)); 116 try (IterableQueryResult res = session.queryAndFetch(query, NXQL.NXQL)) { 117 for (Map<String, Serializable> map : res) { 118 DocumentRef ref = new IdRef((String) map.get(NXQL.ECM_UUID)); 119 try { 120 session.setDocumentSystemProp(ref, "isTrashed", value); 121 updatedRefs.add(ref); 122 } catch (NuxeoException e) { 123 // TODO send to error stream 124 log.warn("Cannot set system property: isTrashed on: " + ref.toString(), e); 125 } 126 } 127 } 128 try { 129 session.save(); 130 if (!updatedRefs.isEmpty()) { 131 fireEvent(session, value ? DOCUMENT_TRASHED : DOCUMENT_UNTRASHED, updatedRefs); 132 } 133 } catch (PropertyException e) { 134 // TODO send to error stream 135 log.warn("Cannot save session", e); 136 } 137 } 138 139 protected void fireEvent(CoreSession session, String eventId, Collection<DocumentRef> refs) { 140 EventService eventService = Framework.getService(EventService.class); 141 DocumentModelList docs = session.getDocuments(refs.toArray(new DocumentRef[0])); 142 docs.forEach(d -> { 143 DocumentEventContext ctx = new DocumentEventContext(session, session.getPrincipal(), d); 144 ctx.setProperty(REPOSITORY_NAME, session.getRepositoryName()); 145 ctx.setProperty(SESSION_ID, session.getSessionId()); 146 ctx.setCategory(EVENT_DOCUMENT_CATEGORY); 147 Event event = ctx.newEvent(eventId); 148 event.setImmediate(false); 149 event.setInline(false); 150 eventService.fireEvent(event); 151 }); 152 } 153 } 154}