2021-04-07 12:38:18 +02:00
package org.gcube.data.access.storagehub.handlers.vres ;
2018-06-20 16:59:41 +02:00
import java.util.ArrayList ;
import java.util.Arrays ;
2020-01-22 16:41:12 +01:00
import java.util.Calendar ;
2021-10-06 19:18:34 +02:00
import java.util.Collections ;
import java.util.HashMap ;
import java.util.LinkedList ;
2018-06-20 16:59:41 +02:00
import java.util.List ;
2021-10-06 19:18:34 +02:00
import java.util.Map ;
2018-06-20 16:59:41 +02:00
import java.util.concurrent.Callable ;
2021-10-06 19:18:34 +02:00
import java.util.stream.Collectors ;
2018-06-20 16:59:41 +02:00
2021-10-06 19:18:34 +02:00
import javax.inject.Inject ;
2018-06-20 16:59:41 +02:00
import javax.jcr.Credentials ;
import javax.jcr.Node ;
2021-10-06 19:18:34 +02:00
import javax.jcr.NodeIterator ;
2018-06-20 16:59:41 +02:00
import javax.jcr.Property ;
import javax.jcr.Repository ;
import javax.jcr.RepositoryException ;
import javax.jcr.Session ;
import javax.jcr.observation.Event ;
import javax.jcr.observation.EventJournal ;
2018-10-25 16:33:23 +02:00
import org.gcube.common.storagehub.model.Excludes ;
2018-06-21 15:01:01 +02:00
import org.gcube.common.storagehub.model.NodeConstants ;
2021-10-06 19:18:34 +02:00
import org.gcube.common.storagehub.model.exceptions.BackendGenericError ;
import org.gcube.common.storagehub.model.items.AbstractFileItem ;
import org.gcube.common.storagehub.model.items.FolderItem ;
2018-06-20 16:59:41 +02:00
import org.gcube.common.storagehub.model.items.Item ;
2020-04-08 21:11:43 +02:00
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter ;
2018-06-20 16:59:41 +02:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
public class VREQueryRetriever implements Callable < List < Item > > {
private static final Logger logger = LoggerFactory . getLogger ( VREQueryRetriever . class ) ;
private static final int CACHE_DIMENSION = 50 ;
2020-01-22 16:41:12 +01:00
2018-06-20 16:59:41 +02:00
private Repository repository ;
private Credentials credentials ;
private Item vreFolder ;
2021-10-06 19:18:34 +02:00
Map < String , Long > cachedList = new HashMap < > ( CACHE_DIMENSION ) ;
long higherTimestamp = Long . MAX_VALUE ;
2018-06-20 16:59:41 +02:00
long lastTimestamp = 0 ;
2021-10-06 19:18:34 +02:00
Node2ItemConverter node2Item ;
2020-01-22 16:41:12 +01:00
2018-06-20 16:59:41 +02:00
2021-10-06 19:18:34 +02:00
public VREQueryRetriever ( Repository repository , Credentials credentials , Node2ItemConverter node2Item , Item vreFolder ) {
2018-06-20 16:59:41 +02:00
super ( ) ;
this . repository = repository ;
this . credentials = credentials ;
this . vreFolder = vreFolder ;
2021-10-06 19:18:34 +02:00
this . node2Item = node2Item ;
2018-06-20 16:59:41 +02:00
}
public List < Item > call ( ) {
2021-10-06 19:18:34 +02:00
logger . debug ( " executing recents task for {} " , vreFolder . getTitle ( ) ) ;
2018-06-20 16:59:41 +02:00
Session ses = null ;
2021-10-06 19:18:34 +02:00
try {
ses = repository . login ( credentials ) ;
//if (cachedList.isEmpty()) {
init ( ses ) ;
/ * } else {
logger . debug ( " redoing recents for {} " , vreFolder . getTitle ( ) ) ;
2018-06-20 16:59:41 +02:00
try {
2020-01-22 16:41:12 +01:00
2018-06-20 16:59:41 +02:00
long timestampToUse = lastTimestamp ;
lastTimestamp = System . currentTimeMillis ( ) ;
long start = System . currentTimeMillis ( ) ;
ses = repository . login ( credentials ) ;
final String [ ] types = { " nthl:workspaceLeafItem " , " nthl:workspaceItem " } ;
2018-07-12 15:44:11 +02:00
EventJournal journalChanged = ses . getWorkspace ( ) . getObservationManager ( ) . getEventJournal ( Event . PROPERTY_CHANGED ^ Event . NODE_REMOVED ^ Event . NODE_MOVED ^ Event . NODE_ADDED , vreFolder . getPath ( ) , true , null , types ) ;
2018-06-20 16:59:41 +02:00
journalChanged . skipTo ( timestampToUse ) ;
2020-01-22 16:41:12 +01:00
2021-10-06 19:18:34 +02:00
logger . debug ( " getting the journal took {} " , System . currentTimeMillis ( ) - start ) ;
2020-01-22 16:41:12 +01:00
2018-07-12 15:44:11 +02:00
int events = 0 ;
2020-01-22 16:41:12 +01:00
2018-06-20 16:59:41 +02:00
while ( journalChanged . hasNext ( ) ) {
2018-07-12 15:44:11 +02:00
events + + ;
2018-06-20 16:59:41 +02:00
Event event = journalChanged . nextEvent ( ) ;
switch ( event . getType ( ) ) {
2020-01-22 16:41:12 +01:00
2018-07-12 15:44:11 +02:00
case Event . NODE_ADDED :
if ( ses . nodeExists ( event . getPath ( ) ) ) {
Node nodeAdded = ses . getNode ( event . getPath ( ) ) ;
if ( nodeAdded . isNodeType ( " nthl:workspaceLeafItem " ) ) {
logger . trace ( " node added event received with name {} " , nodeAdded . getName ( ) ) ;
2018-10-25 16:33:23 +02:00
Item item = node2Item . getItem ( nodeAdded , Arrays . asList ( NodeConstants . ACCOUNTING_NAME ) ) ;
2021-10-06 19:18:34 +02:00
if ( cachedList . get ( event . getIdentifier ( ) ) ! = null )
cachedList . remove ( event . getIdentifier ( ) ) ;
2018-07-12 15:44:11 +02:00
insertItemInTheRightPlace ( item ) ;
}
}
break ;
2020-01-22 16:41:12 +01:00
2018-06-20 16:59:41 +02:00
case Event . PROPERTY_CHANGED :
if ( ses . propertyExists ( event . getPath ( ) ) ) {
Property property = ses . getProperty ( event . getPath ( ) ) ;
if ( property . getName ( ) . equalsIgnoreCase ( " jcr:lastModified " ) ) {
logger . trace ( " event property changed on {} with value {} and parent {} " , property . getName ( ) , property . getValue ( ) . getString ( ) , property . getParent ( ) . getPath ( ) ) ;
String identifier = property . getParent ( ) . getIdentifier ( ) ;
2021-10-06 19:18:34 +02:00
cachedList . remove ( identifier ) ;
2018-10-25 16:33:23 +02:00
Item item = node2Item . getItem ( property . getParent ( ) , Excludes . EXCLUDE_ACCOUNTING ) ;
2018-06-20 16:59:41 +02:00
insertItemInTheRightPlace ( item ) ;
}
}
break ;
case Event . NODE_REMOVED :
logger . trace ( " node removed event received with type {} " , event . getIdentifier ( ) ) ;
2021-10-06 19:18:34 +02:00
if ( cachedList . get ( event . getIdentifier ( ) ) ! = null & &
cachedList . get ( event . getIdentifier ( ) ) < event . getDate ( ) )
cachedList . remove ( event . getIdentifier ( ) ) ;
2018-06-20 16:59:41 +02:00
break ;
case Event . NODE_MOVED :
Node nodeMoved = ses . getNode ( event . getPath ( ) ) ;
logger . trace ( " node moved event received with type {} " , nodeMoved . getPrimaryNodeType ( ) ) ;
if ( nodeMoved . isNodeType ( " nthl:workspaceLeafItem " ) ) {
logger . trace ( " event node moved on {} with path {} " , nodeMoved . getName ( ) , nodeMoved . getPath ( ) ) ;
String identifier = nodeMoved . getIdentifier ( ) ;
2021-10-06 19:18:34 +02:00
String nodePath = ses . getNode ( identifier ) . getPath ( ) ;
if ( cachedList . get ( event . getIdentifier ( ) ) ! = null & &
! nodePath . startsWith ( vreFolder . getPath ( ) ) )
cachedList . remove ( event . getIdentifier ( ) ) ;
2018-06-20 16:59:41 +02:00
}
break ;
default :
throw new Exception ( " error in event handling " ) ;
}
}
2021-10-06 19:18:34 +02:00
2018-07-12 15:44:11 +02:00
logger . trace ( " retrieving event took {} with {} events " , System . currentTimeMillis ( ) - start , events ) ;
2021-10-06 19:18:34 +02:00
2018-06-20 16:59:41 +02:00
} catch ( Exception e ) {
logger . error ( " error getting events for vre {} " , vreFolder . getTitle ( ) , e ) ;
throw new RuntimeException ( e ) ;
} finally {
if ( ses ! = null )
ses . logout ( ) ;
}
2021-10-06 19:18:34 +02:00
} * /
return correctValues ( ses ) ;
} catch ( Exception e ) {
logger . error ( " error preparing recents for folder {} " , vreFolder . getTitle ( ) , e ) ;
return Collections . emptyList ( ) ;
} finally {
if ( ses ! = null )
ses . logout ( ) ;
logger . debug ( " recents task finished " ) ;
}
}
private List < Item > correctValues ( Session ses ) {
logger . debug ( " preparing returning values for {} " , vreFolder . getTitle ( ) ) ;
long start = System . currentTimeMillis ( ) ;
List < Map . Entry < String , Long > > list = new LinkedList < > ( cachedList . entrySet ( ) ) ;
list . sort ( ( c1 , c2 ) - > c1 . getValue ( ) . compareTo ( c2 . getValue ( ) ) * - 1 ) ;
if ( list . size ( ) > CACHE_DIMENSION )
for ( int index = CACHE_DIMENSION - 1 ; index < list . size ( ) ; index + + )
cachedList . remove ( list . get ( index ) . getKey ( ) ) ;
List < String > cachedIds = list . stream ( ) . map ( m - > m . getKey ( ) ) . collect ( Collectors . toList ( ) ) ;
if ( cachedIds . size ( ) > 10 )
cachedIds = cachedIds . subList ( 0 , 10 ) ;
List < Item > result = new ArrayList < > ( 10 ) ;
for ( String id : cachedIds ) {
try {
Item item = node2Item . getItem ( id , ses , Excludes . EXCLUDE_ACCOUNTING ) ;
if ( item ! = null )
result . add ( item ) ;
else logger . warn ( " item with id {} is null " , id ) ;
} catch ( BackendGenericError | RepositoryException e ) { }
2018-06-20 16:59:41 +02:00
}
2021-10-06 19:18:34 +02:00
logger . debug ( " returning values prepared in {} for {} " , System . currentTimeMillis ( ) - start , vreFolder . getTitle ( ) ) ;
return result ;
2018-06-20 16:59:41 +02:00
}
private void insertItemInTheRightPlace ( Item item ) {
2021-10-06 19:18:34 +02:00
long lastModifiedTime = item . getLastModificationTime ( ) . getTime ( ) . getTime ( ) ;
if ( ! ( lastModifiedTime > higherTimestamp & & cachedList . size ( ) > CACHE_DIMENSION ) ) {
cachedList . put ( item . getId ( ) , lastModifiedTime ) ;
if ( lastModifiedTime > higherTimestamp ) higherTimestamp = lastModifiedTime ;
}
}
private void init ( Session ses ) {
try {
long start = System . currentTimeMillis ( ) ;
Calendar now = Calendar . getInstance ( ) ;
now . add ( Calendar . YEAR , - 1 ) ;
lastTimestamp = System . currentTimeMillis ( ) ;
Node vreFolderNode = ses . getNodeByIdentifier ( vreFolder . getId ( ) ) ;
logger . debug ( " starting visiting children for {} " , vreFolder . getTitle ( ) ) ;
visitChildren ( vreFolderNode ) ;
logger . debug ( " initializing recents for {} took {} " , vreFolder . getTitle ( ) , System . currentTimeMillis ( ) - start ) ;
} catch ( Exception e ) {
logger . error ( " error querying vre {} " , vreFolder . getTitle ( ) , e ) ;
throw new RuntimeException ( e ) ;
}
}
private void visitChildren ( Node node ) throws Exception {
NodeIterator nodeIt = node . getNodes ( ) ;
while ( nodeIt . hasNext ( ) ) {
Node child = nodeIt . nextNode ( ) ;
Item item = node2Item . getItem ( child , Excludes . ALL ) ;
if ( item = = null | | item . isHidden ( ) ) continue ;
if ( item instanceof FolderItem )
visitChildren ( child ) ;
else if ( item instanceof AbstractFileItem )
insertItemInTheRightPlace ( item ) ;
2018-06-20 16:59:41 +02:00
}
}
/ * @Override
public void onEvent ( EventIterator events ) {
logger . trace ( " on event called " ) ;
while ( events . hasNext ( ) ) {
Event event = events . nextEvent ( ) ;
try {
logger . trace ( " new event received of type {} on node {} " , event . getType ( ) , event . getIdentifier ( ) ) ;
} catch ( RepositoryException e ) {
logger . error ( " error reading event " , e ) ;
}
}
} * /
}