package org.gcube.data.access.storagehub; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.security.MessageDigest; import java.util.ArrayList; import java.util.Calendar; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Predicate; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.PathNotFoundException; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.lock.Lock; import javax.jcr.lock.LockException; import javax.jcr.query.Query; import org.apache.commons.io.FilenameUtils; import org.apache.jackrabbit.util.ISO9075; import org.apache.jackrabbit.util.Text; import org.gcube.common.storagehub.model.Excludes; import org.gcube.common.storagehub.model.exceptions.BackendGenericError; import org.gcube.common.storagehub.model.exceptions.IdNotFoundException; import org.gcube.common.storagehub.model.exceptions.ItemLockedException; import org.gcube.common.storagehub.model.exceptions.StorageHubException; import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException; import org.gcube.common.storagehub.model.items.AbstractFileItem; import org.gcube.common.storagehub.model.items.ExternalLink; import org.gcube.common.storagehub.model.items.FolderItem; import org.gcube.common.storagehub.model.items.GCubeItem; import org.gcube.common.storagehub.model.items.Item; import org.gcube.common.storagehub.model.items.RootItem; import org.gcube.common.storagehub.model.items.SharedFolder; import org.gcube.common.storagehub.model.storages.MetaInfo; import org.gcube.common.storagehub.model.types.ItemAction; import org.gcube.common.storagehub.model.types.NodeProperty; import org.gcube.data.access.storagehub.accounting.AccountingHandler; import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter; import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter; import org.gcube.data.access.storagehub.handlers.items.builders.FolderCreationParameters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Utils { public final static String SERVICE_NAME = "home-library"; public final static String SERVICE_CLASS = "org.gcube.portlets.user"; private static final String FOLDERS_TYPE = "nthl:workspaceItem"; 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; } public static long getItemCount(Node parent, boolean showHidden, Class nodeType) throws RepositoryException, BackendGenericError{ return getItemList(parent, Excludes.ALL, null, showHidden, nodeType).size(); } 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"); } public static List searchByNameOnFolder(Session ses, String user, AuthorizationChecker authChecker, Node parent, List excludes, Range range, boolean showHidden, boolean excludeTrashed, Class nodeTypeToInclude, String nameParam) throws RepositoryException, BackendGenericError{ String xpath = String.format("/jcr:root%s//element(*,nthl:workspaceItem)[jcr:like(fn:lower-case(@jcr:title), '%s')]",ISO9075.encodePath(parent.getPath()), nameParam.toLowerCase()); //String query = String.format("SELECT * FROM [nthl:workspaceLeafItem] AS node WHERE ISDESCENDANTNODE('%s') ORDER BY node.[jcr:lastModified] DESC ",vreFolder.getPath()); logger.trace("query for search is {}",xpath); long start = System.currentTimeMillis(); @SuppressWarnings("deprecation") Query jcrQuery = ses.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH); NodeChildrenFilterIterator iterator = new NodeChildrenFilterIterator(jcrQuery.execute().getNodes()); logger.trace("[SEARCH] real search took {} millis",(System.currentTimeMillis()-start)); Predicate checker = new Predicate() { @Override public boolean test(Node t) { try { authChecker.checkReadAuthorizationControl(t.getSession(), user, t.getIdentifier()); return true; } catch (UserNotAuthorizedException | BackendGenericError | RepositoryException e) { return false; } } }; return getItemListFromNodeIterator(checker, iterator , excludes, range, showHidden, excludeTrashed, nodeTypeToInclude); } public static List getItemList(Node parent, List excludes, Range range, boolean showHidden, Class nodeTypeToInclude) throws RepositoryException, BackendGenericError{ return getItemList(null, parent, excludes, range, showHidden, nodeTypeToInclude); } public static List getItemList(Predicate checker, Node parent, List excludes, Range range, boolean showHidden, Class nodeTypeToInclude) throws RepositoryException, BackendGenericError{ logger.trace("getting children of node {}", parent.getIdentifier()); long start = System.currentTimeMillis(); NodeChildrenFilterIterator iterator = new NodeChildrenFilterIterator(parent); logger.trace("time to get iterator {}",(System.currentTimeMillis()-start)); return getItemListFromNodeIterator(checker, iterator, excludes, range, showHidden, false, nodeTypeToInclude); } private static List getItemListFromNodeIterator(Predicate checker, NodeChildrenFilterIterator iterator, List excludes, Range range, boolean showHidden, boolean excludeTrashed, Class nodeTypeToInclude) throws RepositoryException, BackendGenericError{ List returnList = new ArrayList(); logger.trace("nodeType is {}",nodeTypeToInclude); int count =0; logger.trace("selected range is {}", range); Node2ItemConverter node2Item= new Node2ItemConverter(); Set duplicateId = new HashSet(); while (iterator.hasNext()){ Node current = iterator.next(); logger.trace("[SEARCH] evaluating node {} ",current.hasProperty(NodeProperty.TITLE.toString())? current.getProperty(NodeProperty.TITLE.toString()):current.getName()); //REMOVE duplicate nodes, in case the indexes are not working if (duplicateId.contains(current.getIdentifier())) { logger.warn("duplicated node found"); continue; } //EXCLUDES node from predicate if (checker!=null && !checker.test(current)) continue; if (isToExclude(current, showHidden)) continue; logger.trace("[SEARCH] current node not excluded {} ",current.hasProperty(NodeProperty.TITLE.toString())? current.getProperty(NodeProperty.TITLE.toString()):current.getName()); if (range==null || (count>=range.getStart() && returnList.size()maxval) maxval = actual; } 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); } } public static Node createFolderInternally(FolderCreationParameters params, AccountingHandler accountingHandler) throws StorageHubException { logger.debug("creating folder {} in {}", params.getName(), params.getParentId()); 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()); FolderItem item = new FolderItem(); Calendar now = Calendar.getInstance(); item.setName(uniqueName); item.setTitle(uniqueName); item.setDescription(params.getDescription()); //TODO: item.setExternalStorage(); //item.setCreationTime(now); boolean hiddenDestNode= false; try { hiddenDestNode = destinationNode.getProperty(NodeProperty.HIDDEN.toString()).getBoolean(); }catch (Throwable e) {} item.setHidden(params.isHidden() || hiddenDestNode); item.setLastAction(ItemAction.CREATED); item.setLastModificationTime(now); item.setLastModifiedBy(params.getUser()); item.setOwner(params.getUser()); item.setPublicItem(false); Node newNode = new Item2NodeConverter().getNode(destinationNode, item); if (accountingHandler!=null) { accountingHandler.createFolderAddObj(uniqueName, item.getClass().getSimpleName(), null, params.getSession(), params.getUser(), destinationNode, false); accountingHandler.createEntryCreate(item.getTitle(), params.getSession(), newNode, params.getUser(), false); } return newNode; } 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); try { item.setHidden(destinationNode.getProperty(NodeProperty.HIDDEN.toString()).getBoolean()); } catch (Throwable e) { item.setHidden(false); } Node newNode = new Item2NodeConverter().getNode(destinationNode, item); if (accountingHandler!=null) { accountingHandler.createFolderAddObj(name, item.getClass().getSimpleName(), null, ses, login, destinationNode, false); accountingHandler.createEntryCreate(item.getTitle(), ses, newNode,login, false); } return newNode; } public static Node createGcubeItemInternally(Session ses, Node destinationNode, String name, String description, String login, GCubeItem gcubeItem, AccountingHandler accountingHandler) throws BackendGenericError { 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()); Node newNode = new Item2NodeConverter().getNode(destinationNode, gcubeItem); //TODO: accounting for GCUBEITEM //accountingHandler.createFolderAddObj(name, item.getClass().getSimpleName(), null, ses, newNode, false); return newNode; } 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()); } public static void setContentFromMetaInfo(AbstractFileItem item, MetaInfo contentInfo) { item.getContent().setSize(contentInfo.getSize()); item.getContent().setRemotePath(contentInfo.getRemotePath()); item.getContent().setSize(contentInfo.getSize()); item.getContent().setPayloadBackend(contentInfo.getPayloadBackend()); } }