2018-05-17 12:51:56 +02:00
package org.gcube.data.access.storagehub ;
import java.io.IOException ;
import java.io.InputStream ;
import java.io.OutputStream ;
2019-07-29 16:26:08 +02:00
import java.net.URL ;
2018-05-17 12:51:56 +02:00
import java.security.MessageDigest ;
import java.util.ArrayList ;
2018-10-25 16:33:23 +02:00
import java.util.Calendar ;
2020-03-17 13:58:37 +01:00
import java.util.HashSet ;
2018-05-17 12:51:56 +02:00
import java.util.List ;
2018-10-25 16:33:23 +02:00
import java.util.Set ;
2021-03-12 10:24:45 +01:00
import java.util.function.Predicate ;
2021-05-04 11:42:02 +02:00
2018-05-17 12:51:56 +02:00
import javax.jcr.Node ;
import javax.jcr.NodeIterator ;
2018-10-25 16:33:23 +02:00
import javax.jcr.PathNotFoundException ;
import javax.jcr.RepositoryException ;
2018-05-17 12:51:56 +02:00
import javax.jcr.Session ;
2019-04-01 17:50:43 +02:00
import javax.jcr.lock.Lock ;
import javax.jcr.lock.LockException ;
2020-01-22 16:41:12 +01:00
import javax.jcr.query.Query ;
2021-05-04 11:42:02 +02:00
2018-10-25 16:33:23 +02:00
import org.apache.commons.io.FilenameUtils ;
2020-01-22 16:41:12 +01:00
import org.apache.jackrabbit.util.ISO9075 ;
2018-10-25 16:33:23 +02:00
import org.apache.jackrabbit.util.Text ;
import org.gcube.common.storagehub.model.Excludes ;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError ;
2021-04-07 12:38:18 +02:00
import org.gcube.common.storagehub.model.exceptions.IdNotFoundException ;
2019-04-01 17:50:43 +02:00
import org.gcube.common.storagehub.model.exceptions.ItemLockedException ;
2021-04-07 12:38:18 +02:00
import org.gcube.common.storagehub.model.exceptions.StorageHubException ;
2020-03-17 13:40:41 +01:00
import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException ;
2021-11-26 17:49:35 +01:00
import org.gcube.common.storagehub.model.items.AbstractFileItem ;
2019-07-29 16:26:08 +02:00
import org.gcube.common.storagehub.model.items.ExternalLink ;
2018-05-17 12:51:56 +02:00
import org.gcube.common.storagehub.model.items.FolderItem ;
2018-10-25 16:33:23 +02:00
import org.gcube.common.storagehub.model.items.GCubeItem ;
2018-05-17 12:51:56 +02:00
import org.gcube.common.storagehub.model.items.Item ;
2021-05-04 11:42:02 +02:00
import org.gcube.common.storagehub.model.items.RootItem ;
2018-06-29 16:59:24 +02:00
import org.gcube.common.storagehub.model.items.SharedFolder ;
2021-11-26 17:49:35 +01:00
import org.gcube.common.storagehub.model.storages.MetaInfo ;
2018-10-25 16:33:23 +02:00
import org.gcube.common.storagehub.model.types.ItemAction ;
2018-05-17 12:51:56 +02:00
import org.gcube.common.storagehub.model.types.NodeProperty ;
import org.gcube.data.access.storagehub.accounting.AccountingHandler ;
2020-04-08 21:11:43 +02:00
import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter ;
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter ;
2021-04-07 12:38:18 +02:00
import org.gcube.data.access.storagehub.handlers.items.builders.FolderCreationParameters ;
2018-05-17 12:51:56 +02:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
public class Utils {
2021-03-31 14:49:47 +02:00
public final static String SERVICE_NAME = " home-library " ;
public final static String SERVICE_CLASS = " org.gcube.portlets.user " ;
2018-05-17 12:51:56 +02:00
private static final String FOLDERS_TYPE = " nthl:workspaceItem " ;
2018-10-25 16:33:23 +02:00
2018-05-17 12:51:56 +02:00
private static final Logger logger = LoggerFactory . getLogger ( Utils . class ) ;
public static String getSecurePassword ( String user ) throws Exception {
String digest = null ;
try {
MessageDigest md = MessageDigest . getInstance ( " MD5 " ) ;
byte [ ] hash = md . digest ( user . getBytes ( " UTF-8 " ) ) ;
//converting byte array to Hexadecimal String
StringBuilder sb = new StringBuilder ( 2 * hash . length ) ;
for ( byte b : hash ) {
sb . append ( String . format ( " %02x " , b & 0xff ) ) ;
}
digest = sb . toString ( ) ;
} catch ( Exception e ) {
logger . error ( " error getting secure password " , e ) ;
}
return digest ;
}
2018-10-25 16:33:23 +02:00
2021-05-04 11:42:02 +02:00
public static long getItemCount ( Node parent , boolean showHidden , Class < ? extends RootItem > nodeType ) throws RepositoryException , BackendGenericError {
2018-10-25 16:33:23 +02:00
return getItemList ( parent , Excludes . ALL , null , showHidden , nodeType ) . size ( ) ;
2018-05-17 12:51:56 +02:00
}
2018-10-25 16:33:23 +02:00
2019-04-01 17:50:43 +02:00
public static void acquireLockWithWait ( Session ses , String nodePath , boolean isDeep , String login , int maxTries ) throws RepositoryException , ItemLockedException {
Lock lock = null ;
int tries = 0 ;
while ( lock = = null & & tries < = maxTries ) {
try {
lock = ses . getWorkspace ( ) . getLockManager ( ) . lock ( nodePath , isDeep , true , 0 , login ) ;
logger . info ( " lock acquired(try n. {}) " , tries ) ;
} catch ( LockException e ) {
try {
if ( maxTries > = tries ) {
int waitTime = ( int ) ( Math . random ( ) * 5000 ) ;
logger . info ( " lock NOT acquired, waiting (try n. {}) for {} " , tries , waitTime ) ;
Thread . sleep ( waitTime ) ;
}
} catch ( InterruptedException e1 ) { }
tries + + ;
}
}
if ( lock = = null ) throw new ItemLockedException ( " the item is locked " ) ;
}
2018-10-25 16:33:23 +02:00
2021-10-13 11:35:19 +02:00
public static < T extends Item > List < T > searchByNameOnFolder ( Session ses , String user , AuthorizationChecker authChecker , Node parent , List < String > excludes , Range range , boolean showHidden , boolean excludeTrashed , Class < ? extends RootItem > nodeTypeToInclude , String nameParam ) throws RepositoryException , BackendGenericError {
2020-01-24 12:30:05 +01:00
String xpath = String . format ( " /jcr:root%s//element(*,nthl:workspaceItem)[jcr:like(fn:lower-case(@jcr:title), '%s')] " , ISO9075 . encodePath ( parent . getPath ( ) ) , nameParam . toLowerCase ( ) ) ;
2018-10-25 16:33:23 +02:00
2020-01-22 16:41:12 +01:00
//String query = String.format("SELECT * FROM [nthl:workspaceLeafItem] AS node WHERE ISDESCENDANTNODE('%s') ORDER BY node.[jcr:lastModified] DESC ",vreFolder.getPath());
2021-10-13 11:35:19 +02:00
logger . trace ( " query for search is {} " , xpath ) ;
2020-03-17 13:40:41 +01:00
long start = System . currentTimeMillis ( ) ;
2021-05-04 11:42:02 +02:00
@SuppressWarnings ( " deprecation " )
2020-01-22 16:41:12 +01:00
Query jcrQuery = ses . getWorkspace ( ) . getQueryManager ( ) . createQuery ( xpath , Query . XPATH ) ;
2020-04-14 18:52:59 +02:00
NodeChildrenFilterIterator iterator = new NodeChildrenFilterIterator ( jcrQuery . execute ( ) . getNodes ( ) ) ;
2021-10-13 11:35:19 +02:00
logger . trace ( " [SEARCH] real search took {} millis " , ( System . currentTimeMillis ( ) - start ) ) ;
2021-03-12 10:24:45 +01:00
Predicate < Node > checker = new Predicate < Node > ( ) {
@Override
public boolean test ( Node t ) {
try {
2021-04-07 12:38:18 +02:00
authChecker . checkReadAuthorizationControl ( t . getSession ( ) , user , t . getIdentifier ( ) ) ;
2021-03-12 10:24:45 +01:00
return true ;
} catch ( UserNotAuthorizedException | BackendGenericError | RepositoryException e ) {
return false ;
}
}
2021-03-15 16:01:14 +01:00
2021-03-12 10:24:45 +01:00
} ;
2021-03-15 16:01:14 +01:00
2021-03-12 10:24:45 +01:00
return getItemListFromNodeIterator ( checker , iterator , excludes , range , showHidden , excludeTrashed , nodeTypeToInclude ) ;
2020-01-22 16:41:12 +01:00
}
2021-03-15 16:01:14 +01:00
2020-01-22 16:41:12 +01:00
2021-05-04 11:42:02 +02:00
public static < T extends Item > List < T > getItemList ( Node parent , List < String > excludes , Range range , boolean showHidden , Class < ? extends RootItem > nodeTypeToInclude ) throws RepositoryException , BackendGenericError {
2021-03-12 10:24:45 +01:00
return getItemList ( null , parent , excludes , range , showHidden , nodeTypeToInclude ) ;
}
2021-03-15 16:01:14 +01:00
2021-05-04 11:42:02 +02:00
public static < T extends Item > List < T > getItemList ( Predicate < Node > checker , Node parent , List < String > excludes , Range range , boolean showHidden , Class < ? extends RootItem > nodeTypeToInclude ) throws RepositoryException , BackendGenericError {
2020-01-22 16:41:12 +01:00
logger . trace ( " getting children of node {} " , parent . getIdentifier ( ) ) ;
2018-05-17 12:51:56 +02:00
long start = System . currentTimeMillis ( ) ;
2020-04-14 18:52:59 +02:00
NodeChildrenFilterIterator iterator = new NodeChildrenFilterIterator ( parent ) ;
2018-05-17 12:51:56 +02:00
logger . trace ( " time to get iterator {} " , ( System . currentTimeMillis ( ) - start ) ) ;
2021-03-12 10:24:45 +01:00
return getItemListFromNodeIterator ( checker , iterator , excludes , range , showHidden , false , nodeTypeToInclude ) ;
2020-01-22 16:41:12 +01:00
}
2021-03-15 16:01:14 +01:00
2021-05-04 11:42:02 +02:00
private static < T extends Item > List < T > getItemListFromNodeIterator ( Predicate < Node > checker , NodeChildrenFilterIterator iterator , List < String > excludes , Range range , boolean showHidden , boolean excludeTrashed , Class < ? extends RootItem > nodeTypeToInclude ) throws RepositoryException , BackendGenericError {
2020-01-22 16:41:12 +01:00
List < T > returnList = new ArrayList < T > ( ) ;
2021-03-15 16:01:14 +01:00
2018-10-25 16:33:23 +02:00
logger . trace ( " nodeType is {} " , nodeTypeToInclude ) ;
2018-05-17 12:51:56 +02:00
int count = 0 ;
logger . trace ( " selected range is {} " , range ) ;
2018-10-25 16:33:23 +02:00
Node2ItemConverter node2Item = new Node2ItemConverter ( ) ;
2020-03-17 13:58:37 +01:00
Set < String > duplicateId = new HashSet < String > ( ) ;
2018-05-17 12:51:56 +02:00
while ( iterator . hasNext ( ) ) {
2020-04-14 18:52:59 +02:00
Node current = iterator . next ( ) ;
2021-03-15 16:01:14 +01:00
2021-10-13 11:35:19 +02:00
logger . trace ( " [SEARCH] evaluating node {} " , current . hasProperty ( NodeProperty . TITLE . toString ( ) ) ? current . getProperty ( NodeProperty . TITLE . toString ( ) ) : current . getName ( ) ) ;
2021-03-15 16:01:14 +01:00
2020-03-17 13:58:37 +01:00
//REMOVE duplicate nodes, in case the indexes are not working
2020-04-08 21:11:43 +02:00
if ( duplicateId . contains ( current . getIdentifier ( ) ) ) {
logger . warn ( " duplicated node found " ) ;
continue ;
}
2021-03-15 16:01:14 +01:00
2021-03-12 10:24:45 +01:00
//EXCLUDES node from predicate
if ( checker ! = null & & ! checker . test ( current ) )
continue ;
2021-03-15 16:01:14 +01:00
2018-05-17 12:51:56 +02:00
if ( isToExclude ( current , showHidden ) )
continue ;
2019-04-01 17:50:43 +02:00
2021-10-13 11:35:19 +02:00
logger . trace ( " [SEARCH] current node not excluded {} " , current . hasProperty ( NodeProperty . TITLE . toString ( ) ) ? current . getProperty ( NodeProperty . TITLE . toString ( ) ) : current . getName ( ) ) ;
2019-04-01 17:50:43 +02:00
2018-05-17 12:51:56 +02:00
if ( range = = null | | ( count > = range . getStart ( ) & & returnList . size ( ) < range . getLimit ( ) ) ) {
2018-10-25 16:33:23 +02:00
T item = node2Item . getFilteredItem ( current , excludes , nodeTypeToInclude ) ;
2020-03-16 16:55:26 +01:00
if ( item = = null | | ( item . isTrashed ( ) & & excludeTrashed ) ) continue ;
2018-05-17 12:51:56 +02:00
returnList . add ( item ) ;
}
count + + ;
2020-03-17 13:58:37 +01:00
duplicateId . add ( current . getIdentifier ( ) ) ;
2018-05-17 12:51:56 +02:00
}
return returnList ;
}
2018-10-25 16:33:23 +02:00
private static boolean isToExclude ( Node node , boolean showHidden ) throws RepositoryException {
2018-05-17 12:51:56 +02:00
return ( ( node . getName ( ) . startsWith ( " rep: " ) | | ( node . getName ( ) . startsWith ( " hl: " ) ) ) | |
2018-10-25 16:33:23 +02:00
( ! showHidden & & node . hasProperty ( NodeProperty . HIDDEN . toString ( ) ) & & node . getProperty ( NodeProperty . HIDDEN . toString ( ) ) . getBoolean ( ) ) | |
( node . getPrimaryNodeType ( ) . getName ( ) . equals ( FOLDERS_TYPE ) & & Constants . FOLDERS_TO_EXLUDE . contains ( node . getName ( ) ) ) ) ;
2018-05-17 12:51:56 +02:00
}
2018-10-25 16:33:23 +02:00
2019-04-01 17:50:43 +02:00
2021-11-26 17:49:35 +01:00
2018-05-17 12:51:56 +02:00
2021-05-04 11:42:02 +02:00
public static void copyStream ( InputStream in , OutputStream out ) throws IOException {
2018-05-17 12:51:56 +02:00
byte [ ] buffer = new byte [ 2048 ] ;
int readcount = 0 ;
while ( ( readcount = in . read ( buffer ) ) ! = - 1 ) {
out . write ( buffer , 0 , readcount ) ;
}
}
2018-10-25 16:33:23 +02:00
public static boolean hasSharedChildren ( Node node ) throws RepositoryException , BackendGenericError {
Node2ItemConverter node2Item = new Node2ItemConverter ( ) ;
2020-04-14 18:52:59 +02:00
NodeChildrenFilterIterator children = new NodeChildrenFilterIterator ( node ) ;
2019-04-01 17:50:43 +02:00
2018-10-25 16:33:23 +02:00
while ( children . hasNext ( ) ) {
2020-04-14 18:52:59 +02:00
Node child = children . next ( ) ;
2018-10-25 16:33:23 +02:00
if ( node2Item . checkNodeType ( child , SharedFolder . class ) ) return true ;
if ( node2Item . checkNodeType ( child , FolderItem . class ) & & hasSharedChildren ( child ) ) return true ;
2018-06-29 16:59:24 +02:00
}
return false ;
2018-10-25 16:33:23 +02:00
}
2021-11-26 17:49:35 +01:00
2018-10-25 16:33:23 +02:00
public static String checkExistanceAndGetUniqueName ( Session ses , Node destination , String name ) throws BackendGenericError {
try {
destination . getNode ( name ) ;
} catch ( PathNotFoundException pnf ) {
return Text . escapeIllegalJcrChars ( name ) ;
} catch ( Exception e ) {
throw new BackendGenericError ( e ) ;
}
try {
String filename = FilenameUtils . getBaseName ( name ) ;
String ext = FilenameUtils . getExtension ( name ) ;
String nameTocheck = ext . isEmpty ( ) ? String . format ( " %s(*) " , filename ) : String . format ( " %s(*).%s " , filename , ext ) ;
2020-01-22 16:41:12 +01:00
logger . trace ( " filename is {}, extension is {} , and name to check is {} " , filename , ext , nameTocheck ) ;
2018-10-25 16:33:23 +02:00
NodeIterator ni = destination . getNodes ( nameTocheck ) ;
int maxval = 0 ;
while ( ni . hasNext ( ) ) {
Node n = ni . nextNode ( ) ;
int actual = Integer . parseInt ( n . getName ( ) . replaceAll ( String . format ( " %s \\ (( \\ d*) \\ ).* " , filename ) , " $1 " ) ) ;
if ( actual > maxval )
maxval = actual ;
}
2018-06-29 16:59:24 +02:00
2018-10-25 16:33:23 +02:00
String newName = ext . isEmpty ( ) ? String . format ( " %s(%d) " , filename , maxval + 1 ) : String . format ( " %s(%d).%s " , filename , maxval + 1 , ext ) ;
return Text . escapeIllegalJcrChars ( newName ) ;
} catch ( Exception e ) {
throw new BackendGenericError ( e ) ;
}
}
2019-04-01 17:50:43 +02:00
2021-03-15 16:01:14 +01:00
2021-04-07 12:38:18 +02:00
public static Node createFolderInternally ( FolderCreationParameters params , AccountingHandler accountingHandler ) throws StorageHubException {
logger . debug ( " creating folder {} in {} " , params . getName ( ) , params . getParentId ( ) ) ;
2021-11-26 17:49:35 +01:00
2021-04-07 12:38:18 +02:00
Node destinationNode ;
try {
destinationNode = params . getSession ( ) . getNodeByIdentifier ( params . getParentId ( ) ) ;
} catch ( RepositoryException e ) {
throw new IdNotFoundException ( params . getParentId ( ) ) ;
}
String uniqueName = Utils . checkExistanceAndGetUniqueName ( params . getSession ( ) , destinationNode , params . getName ( ) ) ;
2019-04-01 17:50:43 +02:00
2018-10-25 16:33:23 +02:00
FolderItem item = new FolderItem ( ) ;
Calendar now = Calendar . getInstance ( ) ;
item . setName ( uniqueName ) ;
item . setTitle ( uniqueName ) ;
2021-04-07 12:38:18 +02:00
item . setDescription ( params . getDescription ( ) ) ;
//TODO: item.setExternalStorage();
2018-10-25 16:33:23 +02:00
//item.setCreationTime(now);
2021-03-15 16:01:14 +01:00
2020-03-16 16:55:26 +01:00
boolean hiddenDestNode = false ;
try {
hiddenDestNode = destinationNode . getProperty ( NodeProperty . HIDDEN . toString ( ) ) . getBoolean ( ) ;
} catch ( Throwable e ) { }
2021-03-15 16:01:14 +01:00
2021-04-07 12:38:18 +02:00
item . setHidden ( params . isHidden ( ) | | hiddenDestNode ) ;
2018-10-25 16:33:23 +02:00
item . setLastAction ( ItemAction . CREATED ) ;
item . setLastModificationTime ( now ) ;
2021-04-07 12:38:18 +02:00
item . setLastModifiedBy ( params . getUser ( ) ) ;
item . setOwner ( params . getUser ( ) ) ;
2018-10-25 16:33:23 +02:00
item . setPublicItem ( false ) ;
2019-04-01 17:50:43 +02:00
2019-02-14 12:01:59 +01:00
Node newNode = new Item2NodeConverter ( ) . getNode ( destinationNode , item ) ;
2020-01-22 16:41:12 +01:00
if ( accountingHandler ! = null ) {
2021-04-07 12:38:18 +02:00
accountingHandler . createFolderAddObj ( uniqueName , item . getClass ( ) . getSimpleName ( ) , null , params . getSession ( ) , params . getUser ( ) , destinationNode , false ) ;
accountingHandler . createEntryCreate ( item . getTitle ( ) , params . getSession ( ) , newNode , params . getUser ( ) , false ) ;
2020-01-22 16:41:12 +01:00
}
2018-10-25 16:33:23 +02:00
return newNode ;
}
2021-03-15 16:01:14 +01:00
2019-07-29 16:26:08 +02:00
public static Node createURLInternally ( Session ses , Node destinationNode , String name , URL value , String description , String login , AccountingHandler accountingHandler ) throws BackendGenericError {
String uniqueName = Utils . checkExistanceAndGetUniqueName ( ses , destinationNode , name ) ;
ExternalLink item = new ExternalLink ( ) ;
Calendar now = Calendar . getInstance ( ) ;
item . setName ( uniqueName ) ;
item . setTitle ( uniqueName ) ;
item . setDescription ( description ) ;
//item.setCreationTime(now);
item . setLastAction ( ItemAction . CREATED ) ;
item . setLastModificationTime ( now ) ;
item . setLastModifiedBy ( login ) ;
item . setOwner ( login ) ;
item . setPublicItem ( false ) ;
item . setValue ( value ) ;
2020-03-16 16:55:26 +01:00
try {
item . setHidden ( destinationNode . getProperty ( NodeProperty . HIDDEN . toString ( ) ) . getBoolean ( ) ) ;
} catch ( Throwable e ) {
item . setHidden ( false ) ;
}
2021-03-15 16:01:14 +01:00
2020-03-16 16:55:26 +01:00
2019-07-29 16:26:08 +02:00
Node newNode = new Item2NodeConverter ( ) . getNode ( destinationNode , item ) ;
2020-01-22 16:41:12 +01:00
if ( accountingHandler ! = null ) {
2021-03-31 14:49:47 +02:00
accountingHandler . createFolderAddObj ( name , item . getClass ( ) . getSimpleName ( ) , null , ses , login , destinationNode , false ) ;
accountingHandler . createEntryCreate ( item . getTitle ( ) , ses , newNode , login , false ) ;
2020-01-22 16:41:12 +01:00
}
2019-07-29 16:26:08 +02:00
return newNode ;
}
2019-04-01 17:50:43 +02:00
2018-10-25 16:33:23 +02:00
public static Node createGcubeItemInternally ( Session ses , Node destinationNode , String name , String description , String login , GCubeItem gcubeItem , AccountingHandler accountingHandler ) throws BackendGenericError {
2019-04-01 17:50:43 +02:00
2018-10-25 16:33:23 +02:00
Calendar now = Calendar . getInstance ( ) ;
gcubeItem . setName ( name ) ;
gcubeItem . setTitle ( name ) ;
gcubeItem . setDescription ( description ) ;
//item.setCreationTime(now);
gcubeItem . setHidden ( false ) ;
gcubeItem . setLastAction ( ItemAction . CREATED ) ;
gcubeItem . setLastModificationTime ( now ) ;
gcubeItem . setLastModifiedBy ( login ) ;
gcubeItem . setOwner ( login ) ;
//to inherit hidden property
//item.setHidden(destinationItem.isHidden());
2019-02-14 12:01:59 +01:00
Node newNode = new Item2NodeConverter ( ) . getNode ( destinationNode , gcubeItem ) ;
2018-10-25 16:33:23 +02:00
//TODO: accounting for GCUBEITEM
//accountingHandler.createFolderAddObj(name, item.getClass().getSimpleName(), null, ses, newNode, false);
return newNode ;
}
2019-04-01 17:50:43 +02:00
2018-10-25 16:33:23 +02:00
public static void setPropertyOnChangeNode ( Node node , String login , ItemAction action ) throws RepositoryException {
node . setProperty ( NodeProperty . LAST_MODIFIED . toString ( ) , Calendar . getInstance ( ) ) ;
node . setProperty ( NodeProperty . LAST_MODIFIED_BY . toString ( ) , login ) ;
node . setProperty ( NodeProperty . LAST_ACTION . toString ( ) , action . name ( ) ) ;
2018-06-29 16:59:24 +02:00
}
2021-03-15 16:01:14 +01:00
2021-11-26 17:49:35 +01:00
public static void setContentFromMetaInfo ( AbstractFileItem item , MetaInfo contentInfo ) {
item . getContent ( ) . setSize ( contentInfo . getSize ( ) ) ;
item . getContent ( ) . setRemotePath ( contentInfo . getRemotePath ( ) ) ;
item . getContent ( ) . setSize ( contentInfo . getSize ( ) ) ;
2021-12-03 16:55:54 +01:00
item . getContent ( ) . setPayloadBackend ( contentInfo . getPayloadBackend ( ) ) ;
2021-11-26 17:49:35 +01:00
}
2018-05-17 12:51:56 +02:00
}