package org.gcube.data.access.storagehub.handlers; import java.text.SimpleDateFormat; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.concurrent.Callable; import javax.jcr.Credentials; import javax.jcr.Node; import javax.jcr.NodeIterator; 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; import javax.jcr.query.Query; import org.apache.jackrabbit.util.ISO9075; import org.gcube.common.storagehub.model.Excludes; import org.gcube.common.storagehub.model.NodeConstants; import org.gcube.common.storagehub.model.items.Item; import org.gcube.common.storagehub.model.types.NodeProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class VREQueryRetriever implements Callable> { private static final Logger logger = LoggerFactory.getLogger(VREQueryRetriever.class); private static final int CACHE_DIMENSION = 50; private Repository repository; private Credentials credentials; private Item vreFolder; List cachedList = new ArrayList<>(CACHE_DIMENSION); long lastTimestamp =0; private Node2ItemConverter node2Item = new Node2ItemConverter(); public VREQueryRetriever(Repository repository, Credentials credentials, Item vreFolder) { super(); this.repository = repository; this.credentials = credentials; this.vreFolder = vreFolder; } public List call() { logger.trace("executing recents task"); Session ses = null; if (lastTimestamp==0) { try { long start = System.currentTimeMillis(); ses = repository.login(credentials); Calendar now = Calendar.getInstance(); now.add(Calendar.YEAR, -1); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.ENGLISH); String formattedDate = formatter.format(now.getTime()); String xpath = String.format("/jcr:root%s//element(*,nthl:workspaceLeafItem)[@jcr:lastModified>xs:dateTime('%s')] order by @jcr:lastModified descending",ISO9075.encodePath(vreFolder.getPath()),formattedDate); //String query = String.format("SELECT * FROM [nthl:workspaceLeafItem] AS node WHERE ISDESCENDANTNODE('%s') ORDER BY node.[jcr:lastModified] DESC ",vreFolder.getPath()); logger.debug("query for recents is {}",xpath); Query jcrQuery = ses.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH); jcrQuery.setLimit(CACHE_DIMENSION); lastTimestamp = System.currentTimeMillis(); NodeIterator it = jcrQuery.execute().getNodes(); logger.debug("query for recents took {}",System.currentTimeMillis()-start); while (it.hasNext()) { Node node = it.nextNode(); //long lastModifiedTimeItem = node.getProperty(NodeProperty.LAST_MODIFIED.toString()).getLong(); //logger.debug("RECENTS - node {} has timestamp {} ", node.getProperty(NodeProperty.TITLE.toString()).getString(), lastModifiedTimeItem); /* if(cachedList.size()<=CACHE_DIMENSION || lastModifiedTimeItem>cachedList.get(CACHE_DIMENSION-1).getLastModificationTime().getTimeInMillis()) { logger.debug("cachedList contains {}",cachedList.size()); if(cachedList.size()>=CACHE_DIMENSION) cachedList.remove(CACHE_DIMENSION-1); Item item =node2Item.getItem(node, Excludes.EXCLUDE_ACCOUNTING); int insertposition =0; for(Item cachedItem: cachedList) { if (cachedItem.getLastModificationTime().before(item.getLastModificationTime())) break; insertposition++; } cachedList.add(insertposition, item); logger.debug("RECENTS - adding item {} with node {} in position {}",item.getTitle(), node.getName(), insertposition); }*/ Item item = node2Item.getItem(node, Excludes.EXCLUDE_ACCOUNTING); logger.debug("RECENTS - adding item {} with timestamp {}",item.getTitle(), item.getLastModificationTime().getTimeInMillis()); cachedList.add(item); } logger.debug("creating objects took {}",System.currentTimeMillis()-start); if (cachedList.size()<=10) return cachedList; else return cachedList.subList(0, 10); } catch (Exception e) { logger.error("error querying vre {}",vreFolder.getTitle(),e); throw new RuntimeException(e); }finally{ if (ses!=null) ses.logout(); logger.trace("recents task finished"); } } else { try { long timestampToUse = lastTimestamp; lastTimestamp = System.currentTimeMillis(); long start = System.currentTimeMillis(); ses = repository.login(credentials); final String[] types = { "nthl:workspaceLeafItem", "nthl:workspaceItem"}; EventJournal journalChanged = ses.getWorkspace().getObservationManager().getEventJournal(Event.PROPERTY_CHANGED^Event.NODE_REMOVED^Event.NODE_MOVED^Event.NODE_ADDED, vreFolder.getPath(), true, null, types); journalChanged.skipTo(timestampToUse); logger.trace("getting the journal took {}",System.currentTimeMillis()-start); int events = 0; while (journalChanged.hasNext()) { events++; Event event = journalChanged.nextEvent(); switch(event.getType()) { 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()); Item item = node2Item.getItem(nodeAdded, Arrays.asList(NodeConstants.ACCOUNTING_NAME)); insertItemInTheRightPlace(item); } } break; 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(); cachedList.removeIf(i -> i.getId().equals(identifier)); Item item = node2Item.getItem(property.getParent(), Excludes.EXCLUDE_ACCOUNTING); insertItemInTheRightPlace(item); } } break; case Event.NODE_REMOVED: logger.trace("node removed event received with type {}", event.getIdentifier()); cachedList.removeIf(i -> { try { return i.getId().equals(event.getIdentifier()) && i.getLastModificationTime().getTime().getTime() i.getId().equals(identifier) && !i.getPath().startsWith(vreFolder.getPath())); } break; default: throw new Exception("error in event handling"); } } if (cachedList.size()>CACHE_DIMENSION) cachedList.subList(51, cachedList.size()).clear(); logger.trace("retrieving event took {} with {} events",System.currentTimeMillis()-start, events); if (cachedList.size()<=10) return cachedList; else return cachedList.subList(0, 10); } catch (Exception e) { logger.error("error getting events for vre {}",vreFolder.getTitle(),e); throw new RuntimeException(e); }finally{ if (ses!=null) ses.logout(); } } } private void insertItemInTheRightPlace(Item item) { Iterator it = cachedList.iterator(); int index =0; while (it.hasNext()) { Item inListItem = it.next(); if (item.getLastModificationTime().getTime().getTime()>=inListItem.getLastModificationTime().getTime().getTime()) break; index++; } if (index