Lucio Lelii 6 years ago
commit f50cc7582d

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>storagehub-webapp</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

@ -0,0 +1,6 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding//src/test/java=UTF-8
encoding//src/test/resources=UTF-8
encoding/<project>=UTF-8

@ -0,0 +1,5 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

@ -0,0 +1 @@
${gcube.license}

@ -0,0 +1,66 @@
The gCube System - ${name}
--------------------------------------------------
${description}
${gcube.description}
${gcube.funding}
Version
--------------------------------------------------
${version} (${buildDate})
Please see the file named "changelog.xml" in this directory for the release notes.
Authors
--------------------------------------------------
* Lucio Lelii (lucio.lelii-AT-isti.cnr.it), CNR Pisa,
Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo".
Maintainers
-----------
* Lucio Lelii (lucio.lelii-AT-isti.cnr.it), CNR Pisa,
Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo".
Download information
--------------------------------------------------
Source code is available from SVN:
${scm.url}
Binaries can be downloaded from the gCube website:
${gcube.website}
Installation
--------------------------------------------------
Installation documentation is available on-line in the gCube Wiki:
${gcube.wikiRoot}/Home_Library_2.0_API_Framework_Specification
Documentation
--------------------------------------------------
Documentation is available on-line in the gCube Wiki:
${gcube.wikiRoot}/StorageHub_API_Framework_Specification
Support
--------------------------------------------------
Bugs and support requests can be reported in the gCube issue tracking tool:
${gcube.issueTracking}
Licensing
--------------------------------------------------
This software is licensed under the terms you may find in the file named "LICENSE" in this directory.

@ -0,0 +1,6 @@
<ReleaseNotes>
<Changeset component="org.gcube.data-access.storagehub-webapp.1.0.0"
date="2015-07-01">
<Change>First commit</Change>
</Changeset>
</ReleaseNotes>

@ -0,0 +1,32 @@
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>servicearchive</id>
<formats>
<format>tar.gz</format>
</formats>
<baseDirectory>/</baseDirectory>
<fileSets>
<fileSet>
<directory>${distroDirectory}</directory>
<outputDirectory>/</outputDirectory>
<useDefaultExcludes>true</useDefaultExcludes>
<includes>
<include>README</include>
<include>LICENSE</include>
<include>changelog.xml</include>
<include>profile.xml</include>
</includes>
<fileMode>755</fileMode>
<filtered>true</filtered>
</fileSet>
</fileSets>
<files>
<file>
<source>target/${build.finalName}.war</source>
<outputDirectory>/${artifactId}</outputDirectory>
</file>
</files>
</assembly>

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<Resource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ID></ID>
<Type>Service</Type>
<Profile>
<Description>Storage Hub Webapp</Description>
<Class>DataAccess</Class>
<Name>${artifactId}</Name>
<Version>1.0.0</Version>
<Packages>
<Software>
<Name>${artifactId}</Name>
<Version>${version}</Version>
<MavenCoordinates>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<version>${version}</version>
</MavenCoordinates>
<Files>
<File>${build.finalName}.jar</File>
</Files>
</Software>
</Packages>
</Profile>
</Resource>

@ -0,0 +1,332 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>maven-parent</artifactId>
<groupId>org.gcube.tools</groupId>
<version>1.0.0</version>
<relativePath />
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.gcube.data.access</groupId>
<artifactId>storagehub</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>storagehub</name>
<packaging>war</packaging>
<properties>
<jackrabbit.version>2.14.0</jackrabbit.version>
<tomcat.version>7.0.40</tomcat.version>
<jetty.version>6.1.26</jetty.version>
<tika.version>1.7</tika.version>
<slf4j.api.version>1.6.6</slf4j.api.version>
<slf4j.version>1.7.4</slf4j.version> <!-- sync with logback version -->
<logback.version>1.0.12</logback.version>
<distroDirectory>${project.basedir}/distro</distroDirectory>
<description>REST web service for Jackrabbit</description>
<warname>storagehub</warname>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>maven-smartgears-bom</artifactId>
<version>LATEST</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>common-authorization</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-encryption</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope-maps</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>storagehub-model</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.6</version>
</dependency>
<dependency>
<groupId>gov.nih.imagej</groupId>
<artifactId>imagej</artifactId>
<version>1.47</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<!-- JCR dependencies -->
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-api</artifactId>
<version>${jackrabbit.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-core</artifactId>
<version>${jackrabbit.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-jcr-server</artifactId>
<version>${jackrabbit.version}</version>
</dependency>
<!-- jersey -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.13</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers.glassfish</groupId>
<artifactId>jersey-gf-cdi</artifactId>
<version>2.13</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<!-- weld -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet</artifactId>
<version>2.2.10.Final</version>
</dependency>
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jandex</artifactId>
<version>1.2.2.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.13</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.13</version>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901.jdbc4</version>
<scope>runtime</scope>
</dependency>
<!-- Storage dependencies -->
<dependency>
<groupId>org.gcube.contentmanagement</groupId>
<artifactId>storage-manager-core</artifactId>
<version>[2.0.0-SNAPSHOT,3.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.gcube.contentmanagement</groupId>
<artifactId>storage-manager-wrapper</artifactId>
<version>[2.0.0-SNAPSHOT,3.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-simple</artifactId>
<version>2.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.8.2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyclient</artifactId>
<version>10.8.2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.jeeunit</groupId>
<artifactId>jeeunit</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
<version>2.2.10.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${artifactId}</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<target>1.8</target>
<source>1.8</source>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>${distroDirectory}/descriptor.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>servicearchive</id>
<phase>install</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,38 @@
package org.gcube.data.access.storagehub;
import java.util.Arrays;
import javax.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.Session;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.SharedFolder;
import org.gcube.data.access.storagehub.handlers.ItemHandler;
@Singleton
public class AuthorizationChecker {
public void checkReadAuthorizationControl(Session session, String id) throws Exception{
Node node = session.getNodeByIdentifier(id);
Item item = ItemHandler.getItem(node, Arrays.asList("hl:accounting","jcr:content"));
if (item.isShared()) {
SharedFolder parentShared = retrieveSharedFolderParent(item, session);
if (!parentShared.getUsers().getValue().containsKey(AuthorizationProvider.instance.get().getClient().getId()))
throw new IllegalAccessException("Insufficent Provileges to read node with id "+id);
} else if (!node.getProperty("hl:portalLogin").getString().equals(AuthorizationProvider.instance.get().getClient().getId()))
throw new IllegalAccessException("Insufficent Provileges to read node with id "+id);
}
private SharedFolder retrieveSharedFolderParent(Item item, Session session) throws Exception{
if (item instanceof SharedFolder) return (SharedFolder)item;
else
return retrieveSharedFolderParent(ItemHandler.getItem(session.getNodeByIdentifier(item.getParentId()), Arrays.asList("hl:accounting","jcr:content")), session);
}
}

@ -0,0 +1,15 @@
package org.gcube.data.access.storagehub;
public class Constants {
public static final String VRE_FOLDER_PARENT_NAME = "MySpecialFolders";
public static final String TRASH_ROOT_FOLDER_NAME ="Trash";
public static final String QUERY_LANGUAGE ="JCR-SQL2";
public static final String ADMIN_PARAM_NAME ="admin-username";
public static final String ADMIN_PARAM_PWD ="admin-pwd";
}

@ -0,0 +1,13 @@
package org.gcube.data.access.storagehub;
import lombok.Data;
@Data
public class MetaInfo {
long size;
String storageId;
}

@ -0,0 +1,141 @@
package org.gcube.data.access.storagehub;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MultipleOutputStream {
private Logger logger = LoggerFactory.getLogger(MultipleOutputStream.class);
private MyPipedInputStream[] pipedInStreams;
private InputStream is;
private MyPipedOututStream[] pipedOutStreams;
private int index=0;
public MultipleOutputStream(InputStream is, int number) throws IOException{
this.is = is;
logger.debug("requested {} piped streams ",number);
pipedInStreams = new MyPipedInputStream[number];
pipedOutStreams = new MyPipedOututStream[number];
for (int i =0; i<number; i++) {
pipedOutStreams[i] = new MyPipedOututStream();
pipedInStreams[i] = new MyPipedInputStream(pipedOutStreams[i]);
}
}
public void startWriting() throws Exception{
try(BufferedInputStream bis = new BufferedInputStream(is)){
byte[] buf = new byte[65536];
int read=-1;
int writeTot = 0;
while ((read =bis.read(buf))!=-1){
for (int i=0; i< pipedInStreams.length; i++) {
if (!pipedInStreams[i].isClosed()) {
logger.debug("writing into piped stream {} ",i);
pipedOutStreams[i].write(buf, 0, read);
}
}
writeTot+= read;
if (allOutStreamClosed()) {
logger.debug("all streams created are closed");
break;
} else logger.debug("NOT all streams created are closed");
}
for (int i=0; i< pipedOutStreams.length; i++) {
if (!pipedOutStreams[i].isClosed()) {
logger.debug("closing outputstream {}",i);
pipedOutStreams[i].close();
}
}
logger.debug("total written "+writeTot);
}
}
private boolean allOutStreamClosed() {
for (int i=0; i<pipedOutStreams.length; i++) {
if (!pipedOutStreams[i].isClosed())
return false;
}
return true;
}
public synchronized InputStream get() {
logger.debug("requesting piped streams {}",index);
if (index>=pipedInStreams.length) return null;
return pipedInStreams[index++];
}
public class MyPipedOututStream extends PipedOutputStream{
boolean close = false;
@Override
public void close() throws IOException {
this.close = true;
super.close();
}
/**
* @return the close
*/
public boolean isClosed() {
return close;
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
try{
super.write(b, off, len);
}catch(IOException io){
this.close = true;
}
}
}
public class MyPipedInputStream extends PipedInputStream{
boolean close = false;
public MyPipedInputStream(PipedOutputStream src) throws IOException {
super(src);
}
@Override
public void close() throws IOException {
this.close = true;
logger.debug(Thread.currentThread().getName()+" close MyPipedInputStream");
super.close();
}
/**
* @return the close
*/
public boolean isClosed() {
return close;
}
}
}

@ -0,0 +1,29 @@
package org.gcube.data.access.storagehub;
public class Range {
private int start;
private int limit;
public Range(int start, int limit) {
super();
this.start = start;
this.limit = limit;
}
public int getStart() {
return start;
}
public int getLimit() {
return limit;
}
@Override
public String toString() {
return "Range [start=" + start + ", limit=" + limit + "]";
}
}

@ -0,0 +1,31 @@
package org.gcube.data.access.storagehub;
import javax.inject.Singleton;
import javax.jcr.Repository;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.gcube.data.access.storagehub.services.RepositoryInitializer;
@Singleton
public class RepositoryInitializerImpl implements RepositoryInitializer{
private Repository repository;
@Override
public Repository getRepository(){
return repository;
}
public RepositoryInitializerImpl() throws Exception{
InitialContext context = new InitialContext();
Context environment = (Context) context.lookup("java:comp/env");
repository = (Repository) environment.lookup("jcr/repository");
}
}

@ -0,0 +1,46 @@
package org.gcube.data.access.storagehub;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.StreamingOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SingleFileStreamingOutput implements StreamingOutput {
private static final Logger log = LoggerFactory.getLogger(SingleFileStreamingOutput.class);
InputStream streamToWrite;
public SingleFileStreamingOutput(InputStream streamToWrite) {
super();
this.streamToWrite = streamToWrite;
}
/**
* Overriding the write method to write request data directly to Jersey outputStream .
* @param outputStream
* @throws IOException
* @throws WebApplicationException
*/
@Override
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
log.debug("writing StreamOutput");
copy(streamToWrite, outputStream);
log.debug("StreamOutput written");
}
private void copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[2048];
int readcount = 0;
while ((readcount=in.read(buffer))!=-1) {
out.write(buffer, 0, readcount);
}
}
}

@ -0,0 +1,36 @@
package org.gcube.data.access.storagehub;
import java.util.Map;
import java.util.WeakHashMap;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.contentmanagement.blobstorage.service.IClient;
import org.gcube.contentmanager.storageclient.model.protocol.smp.Handler;
import org.gcube.contentmanager.storageclient.wrapper.AccessType;
import org.gcube.contentmanager.storageclient.wrapper.MemoryType;
import org.gcube.contentmanager.storageclient.wrapper.StorageClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StorageFactory {
public final static String SERVICE_NAME = "home-library";
public final static String SERVICE_CLASS = "org.gcube.portlets.user";
private static Map<String, IClient> clientUserMap = new WeakHashMap<String, IClient>();
private static Logger log = LoggerFactory.getLogger(StorageFactory.class);
public static IClient getGcubeStorage(){
String login = AuthorizationProvider.instance.get().getClient().getId();
if (!clientUserMap.containsKey(login)){
IClient storage = new StorageClient(SERVICE_CLASS, SERVICE_NAME,
login, AccessType.SHARED, MemoryType.PERSISTENT).getClient();
log.info("******* Storage activateProtocol for Storage **********");
Handler.activateProtocol();
clientUserMap.put(login, storage);
return storage;
} else return clientUserMap.get(login);
}
}

@ -0,0 +1,28 @@
package org.gcube.data.access.storagehub;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import org.gcube.data.access.storagehub.services.ItemsCreator;
import org.gcube.data.access.storagehub.services.ItemsManager;
import org.gcube.data.access.storagehub.services.WorkspaceManager;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
@Path("workspace")
public class StorageHub extends Application {
@Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<Class<?>>();
// register resources and features
classes.add(MultiPartFeature.class);
classes.add(WorkspaceManager.class);
classes.add(ItemsManager.class);
classes.add(ItemsCreator.class);
return classes;
}
}

@ -0,0 +1,183 @@
package org.gcube.data.access.storagehub;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Session;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.storagehub.model.Paths;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.types.NodeProperty;
import org.gcube.contentmanager.storageclient.wrapper.AccessType;
import org.gcube.contentmanager.storageclient.wrapper.MemoryType;
import org.gcube.contentmanager.storageclient.wrapper.StorageClient;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.handlers.ItemHandler;
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 List<String> FOLDERS_TO_EXLUDE = Arrays.asList(Constants.VRE_FOLDER_PARENT_NAME, Constants.TRASH_ROOT_FOLDER_NAME);
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) throws Exception{
NodeIterator iterator = parent.getNodes();
long count=0;
while (iterator.hasNext()){
Node current = iterator.nextNode();
if (isToExclude(current, showHidden))
continue;
count++;
}
return count;
}
public static <T extends Item> List<T> getItemList(Node parent, List<String> excludes, Range range, boolean showHidden) throws Exception{
List<T> returnList = new ArrayList<T>();
long start = System.currentTimeMillis();
NodeIterator iterator = parent.getNodes();
logger.trace("time to get iterator {}",(System.currentTimeMillis()-start));
int count =0;
logger.trace("selected range is {}", range);
while (iterator.hasNext()){
Node current = iterator.nextNode();
if (isToExclude(current, showHidden))
continue;
if (range==null || (count>=range.getStart() && returnList.size()<range.getLimit())) {
T item = ItemHandler.getItem(current, excludes);
returnList.add(item);
}
count++;
}
return returnList;
}
private static boolean isToExclude(Node node, boolean showHidden) throws Exception{
return ((node.getName().startsWith("rep:") || (node.getName().startsWith("hl:"))) ||
(!showHidden && node.getProperty(NodeProperty.HIDDEN.toString()).getBoolean()) ||
(node.getPrimaryNodeType().getName().equals(FOLDERS_TYPE) && FOLDERS_TO_EXLUDE.contains(node.getName())));
}
public static org.gcube.common.storagehub.model.Path getHomePath(){
return Paths.getPath(String.format("/Home/%s/Workspace",AuthorizationProvider.instance.get().getClient().getId()));
}
public static StorageClient getStorageClient(String login){
return new StorageClient(SERVICE_CLASS, SERVICE_NAME, login, AccessType.SHARED, MemoryType.PERSISTENT);
}
public static Deque<Item> getAllNodesForZip(FolderItem directory, Session session, AccountingHandler accountingHandler) throws Exception{
Deque<Item> queue = new LinkedList<Item>();
Node currentNode = session.getNodeByIdentifier(directory.getId());
queue.push(directory);
Deque<Item> tempQueue = new LinkedList<Item>();
logger.debug("adding directory {}",directory.getPath());
for (Item item : Utils.getItemList(currentNode,null, null, false)){
if (item instanceof FolderItem)
tempQueue.addAll(getAllNodesForZip((FolderItem) item, session, accountingHandler));
else if (item instanceof AbstractFileItem){
logger.debug("adding file {}",item.getPath());
AbstractFileItem fileItem = (AbstractFileItem) item;
accountingHandler.createReadObj(fileItem.getTitle(), session, session.getNodeByIdentifier(item.getId()), false);
queue.addLast(item);
}
}
queue.addAll(tempQueue);
return queue;
}
public static void zipNode(ZipOutputStream zos, Deque<Item> queue, String login, org.gcube.common.storagehub.model.Path originalPath) throws Exception{
logger.trace("originalPath is {}",originalPath.toPath());
org.gcube.common.storagehub.model.Path actualPath = Paths.getPath("");
while (!queue.isEmpty()) {
Item item = queue.pop();
if (item instanceof FolderItem) {
actualPath = Paths.getPath(item.getPath());
logger.trace("actualPath is {}",actualPath.toPath());
String name = Paths.remove(actualPath, originalPath).toPath().replaceFirst("/", "");
logger.trace("writing dir {}",name);
zos.putNextEntry(new ZipEntry(name));
zos.closeEntry();
} else if (item instanceof AbstractFileItem){
InputStream streamToWrite = Utils.getStorageClient(login).getClient().get().RFileAsInputStream(((AbstractFileItem)item).getContent().getStorageId());
if (streamToWrite == null){
logger.warn("discarding item {} ",item.getName());
continue;
}
try(BufferedInputStream is = new BufferedInputStream(streamToWrite)){
String name = Paths.remove(actualPath, originalPath).toPath()+item.getName().replaceFirst("/", "");
logger.trace("writing file {}",name);
zos.putNextEntry(new ZipEntry(name));
copyStream(is, zos);
}catch (Exception e) {
logger.warn("error writing item {}", item.getName(),e);
} finally{
zos.closeEntry();
}
}
}
}
private static void copyStream(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[2048];
int readcount = 0;
while ((readcount=in.read(buffer))!=-1) {
out.write(buffer, 0, readcount);
}
}
}

@ -0,0 +1,71 @@
package org.gcube.data.access.storagehub.accounting;
public enum AccountingFields {
USER{
@Override
public String toString() {
return "hl:user";
}
},
DATE{
@Override
public String toString() {
return "hl:date";
}
},
ITEM_NAME{
@Override
public String toString() {
return "hl:itemName";
}
},
FROM_PATH{
@Override
public String toString() {
return "hl:fromPath";
}
},
OLD_ITEM_NAME{
@Override
public String toString() {
return "hl:oldItemName";
}
},
NEW_ITEM_NAME{
@Override
public String toString() {
return "hl:newItemName";
}
},
MEMBERS{
@Override
public String toString() {
return "hl:members";
}
},
FOLDER_ITEM_TYPE{
@Override
public String toString() {
return "hl:folderItemType";
}
},
MIME_TYPE{
@Override
public String toString() {
return "hl:mimeType";
}
},
ITEM_TYPE{
@Override
public String toString() {
return "hl:itemType";
}
},
VERSION{
@Override
public String toString() {
return "hl:version";
}
},
}

@ -0,0 +1,60 @@
package org.gcube.data.access.storagehub.accounting;
import java.util.Calendar;
import java.util.UUID;
import javax.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.version.Version;
import javax.jcr.version.VersionManager;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.storagehub.model.items.nodes.accounting.AccountingEntryType;
import org.gcube.common.storagehub.model.types.NodeProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class AccountingHandler {
/*@Attribute("hl:user")
@Attribute("hl:date")
@Attribute("hl:version")*/
private static final Logger logger = LoggerFactory.getLogger(AccountingHandler.class);
public void createReadObj(String title, Session ses, Node node, boolean saveHistory ) {
try {
Node directoryNode = node.getParent();
if (!directoryNode.hasNode(NodeProperty.ACCOUNTING.toString())){
directoryNode.addNode(NodeProperty.ACCOUNTING.toString(), NodeProperty.NT_ACCOUNTING.toString());
}
Node accountingNodeParent = directoryNode.getNode(NodeProperty.ACCOUNTING.toString());
Node accountingNode = accountingNodeParent.addNode(UUID.randomUUID().toString(),AccountingEntryType.READ.getNodeTypeDefinition());
accountingNode.setProperty("hl:user", AuthorizationProvider.instance.get().getClient().getId());
accountingNode.setProperty("hl:date", Calendar.getInstance());
accountingNode.setProperty("hl:itemName", title);
try {
VersionManager vManager = ses.getWorkspace().getVersionManager();
//VersionManager versionManager = session.getWorkspace().getVersionManager();
//Version version = versionManager.checkin(node.getPath());
Version version = vManager.getBaseVersion(node.getNode("jcr:content").getPath());
accountingNode.setProperty("hl:version", version.getName());
}catch(UnsupportedRepositoryOperationException uropex) {
logger.warn("version cannot be retrieved", uropex);
}
if (saveHistory) ses.save();
} catch (RepositoryException e) {
logger.warn("error trying to retrieve accountign node",e);
}
}
}

@ -0,0 +1,47 @@
package org.gcube.data.access.storagehub.handlers;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.gcube.common.storagehub.model.annotations.RootNode;
import org.gcube.common.storagehub.model.items.Item;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ClassHandler {
private static Logger log = LoggerFactory.getLogger(ClassHandler.class);
private Reflections reflection = new Reflections();
private Map<String, Class<? extends Item>> classMap = new HashMap<String, Class<? extends Item>>();
private Map<Class<? extends Item>, String> typeMap = new HashMap<Class<? extends Item>, String>();
public ClassHandler() {
Set<Class<?>> classesAnnotated = reflection.getTypesAnnotatedWith(RootNode.class);
for (Class<?> clazz: classesAnnotated ){
if (Item.class.isAssignableFrom(clazz))
for (String value: clazz.getAnnotation(RootNode.class).value()){
log.debug("loading class {} with value {} ", clazz, value );
classMap.put(value, (Class<? extends Item>) clazz);
typeMap.put((Class<? extends Item>) clazz, value);
}
}
}
public Class<? extends Item> get(String nodeType){
if (classMap.containsKey(nodeType)) return classMap.get(nodeType);
throw new RuntimeException("mapping not found for nodetype "+ nodeType);
}
public String getNodeType(Class<? extends Item> clazz){
if (typeMap.containsKey(clazz)) return typeMap.get(clazz);
throw new RuntimeException("mapping not found for nodetype "+ clazz.getSimpleName());
}
}

@ -0,0 +1,398 @@
package org.gcube.data.access.storagehub.handlers;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import org.apache.jackrabbit.util.Text;
import org.apache.jackrabbit.value.BinaryValue;
import org.apache.jackrabbit.value.BooleanValue;
import org.apache.jackrabbit.value.DateValue;
import org.apache.jackrabbit.value.LongValue;
import org.apache.jackrabbit.value.StringValue;
import org.gcube.common.storagehub.model.annotations.Attribute;
import org.gcube.common.storagehub.model.annotations.AttributeRootNode;
import org.gcube.common.storagehub.model.annotations.ListNodes;
import org.gcube.common.storagehub.model.annotations.MapAttribute;
import org.gcube.common.storagehub.model.annotations.NodeAttribute;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.SharedFolder;
import org.gcube.common.storagehub.model.items.TrashItem;
import org.reflections.Configuration;
import org.reflections.Reflections;
import org.reflections.util.ConfigurationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ItemHandler {
private static final Logger logger = LoggerFactory.getLogger(ItemHandler.class);
private static ClassHandler classHandler = new ClassHandler();
private static HashMap<Class, Map<String, Class>> typeToSubtypeMap = new HashMap<>();
public static <T extends Item> T getItem(Node node, List<String> excludes) throws Exception {
@SuppressWarnings("unchecked")
Class<T> classToHandle = (Class<T>)classHandler.get(node.getPrimaryNodeType().getName());
T item = classToHandle.newInstance();
item.setId(node.getIdentifier());
item.setName(Text.unescapeIllegalJcrChars(node.getName()));
item.setPath(Text.unescapeIllegalJcrChars(node.getPath()));
item.setLocked(node.isLocked());
item.setPrimaryType(node.getPrimaryNodeType().getName());
Item parent = null ;
if (item instanceof SharedFolder) {
logger.debug("I'm in a Shared Folder");
item.setShared(true);
}else {
try {
parent = ItemHandler.getItem(node.getParent(), Arrays.asList("hl:accounting","jcr:content"));
item.setShared(parent.isShared());
} catch(Exception e) {
item.setShared(false);
}
}
if (item instanceof TrashItem)
item.setTrashed(true);
else {
try {
if (parent==null)
parent = ItemHandler.getItem(node.getParent(), Arrays.asList("hl:accounting","jcr:content"));
item.setTrashed(parent.isTrashed());
} catch(Exception e) {
item.setTrashed(false);
}
}
try{
item.setParentId(node.getParent().getIdentifier());
item.setParentPath(node.getParent().getPath());
}catch (Throwable e) {
logger.info("Root node doesn't have a parent");
}
for (Field field : retrieveAllFields(classToHandle)){
if (field.isAnnotationPresent(Attribute.class)){
Attribute attribute = field.getAnnotation(Attribute.class);
field.setAccessible(true);
try{
Class<?> returnType = field.getType();
field.set(item, getPropertyValue(returnType, node.getProperty(attribute.value())));
}catch(PathNotFoundException e){
logger.debug("the current node dosn't contain {} property",attribute.value());
} catch (Exception e ) {
logger.warn("error setting value",e);
}
} else if (field.isAnnotationPresent(NodeAttribute.class)){
String fieldNodeName = field.getAnnotation(NodeAttribute.class).value();
//for now it excludes only first level node
if (excludes!=null && excludes.contains(fieldNodeName)) continue;
logger.debug("retrieving field node "+field.getName());
field.setAccessible(true);
try{
Node fieldNode = node.getNode(fieldNodeName);
logger.debug("looking in node {} searched with {}",fieldNode.getName(),fieldNodeName);
field.set(item, iterateNodeAttributeFields(field.getType(), fieldNode));
}catch(PathNotFoundException e){
logger.debug("the current node dosn't contain {} node",fieldNodeName);
} catch (Exception e ) {
logger.warn("error setting value",e);
}
}
}
return item;
}
private static <T> T iterateNodeAttributeFields(Class<T> clazz, Node node) throws Exception{
T obj = clazz.newInstance();
for (Field field : retrieveAllFields(clazz)){
if (field.isAnnotationPresent(Attribute.class)){
Attribute attribute = field.getAnnotation(Attribute.class);
field.setAccessible(true);
try{
@SuppressWarnings("rawtypes")
Class returnType = field.getType();
field.set(obj, getPropertyValue(returnType, node.getProperty(attribute.value())));
logger.debug("found field {} of type annotated as ListNodes in class {} on node {}", field.getName(), clazz.getName(), node.getName());
}catch(PathNotFoundException e){
logger.debug("the current node dosn't contain {} property",attribute.value());
} catch (Exception e ) {
logger.warn("error setting value",e);
}
} else if (field.isAnnotationPresent(MapAttribute.class)){
//logger.debug("found field {} of type annotated as MapAttribute in class {}", field.getName(), clazz.getName());
field.setAccessible(true);
String exclude = field.getAnnotation(MapAttribute.class).excludeStartWith();
Map<String, Object> mapToset = new HashMap<String, Object>();
PropertyIterator iterator = node.getProperties();
if (iterator!=null) {
while (iterator.hasNext()){
Property prop = iterator.nextProperty();
if (!exclude.isEmpty() && prop.getName().startsWith(exclude)) continue;
try{
mapToset.put(prop.getName(), getPropertyValue(prop));
}catch(PathNotFoundException e){
logger.debug("the property [] is not mapped",prop.getName());
} catch (Exception e ) {
logger.warn("error setting value",e);
}
}
}
field.set(obj, mapToset);
} else if (field.isAnnotationPresent(ListNodes.class)){
logger.debug("found field {} of type annotated as ListNodes in class {} on node {}", field.getName(), clazz.getName(), node.getName());
field.setAccessible(true);
String exclude = field.getAnnotation(ListNodes.class).excludeTypeStartWith();
String include = field.getAnnotation(ListNodes.class).includeTypeStartWith();
Class listType = field.getAnnotation(ListNodes.class).listClass();
Map<String, Class> subTypesMap = Collections.emptyMap();
if (!typeToSubtypeMap.containsKey(listType)) {
Configuration config = new ConfigurationBuilder().forPackages(listType.getPackage().getName());
Reflections reflections = new Reflections(config);
Set<Class> subTypes = reflections.getSubTypesOf(listType);
if (subTypes.size()>0) {
subTypesMap = new HashMap<>();
for (Class subtype: subTypes)
if (subtype.isAnnotationPresent(AttributeRootNode.class)) {
AttributeRootNode attributeRootNode = (AttributeRootNode)subtype.getAnnotation(AttributeRootNode.class);
subTypesMap.put(attributeRootNode.value(), subtype);
}
} else logger.debug("no subtypes found for {}",listType.getName());
typeToSubtypeMap.put(listType, subTypesMap);
} else {
logger.info("subtypes already found in cache");
subTypesMap = typeToSubtypeMap.get(listType);
}
List<Object> toSetList = new ArrayList<>();
NodeIterator iterator = node.getNodes();
while (iterator.hasNext()){
Node currentNode = iterator.nextNode();
String primaryType = currentNode.getPrimaryNodeType().getName();
logger.debug("the current node {} has a list",currentNode.getName());
if (!include.isEmpty() && !primaryType.startsWith(include))
continue;
if (!exclude.isEmpty() && primaryType.startsWith(exclude))
continue;
if (subTypesMap.containsKey(primaryType))
toSetList.add(iterateNodeAttributeFields(subTypesMap.get(primaryType), currentNode));
else toSetList.add(iterateNodeAttributeFields(listType, currentNode));
}
if (toSetList.size()!=0) field.set(obj, toSetList);
}
}
return obj;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private static Object getPropertyValue(Class returnType, Property prop) throws Exception{
if (returnType.equals(String.class)) return prop.getString();
if (returnType.isEnum()) return Enum.valueOf(returnType, prop.getString());
if (returnType.equals(Calendar.class)) return prop.getDate();
if (returnType.equals(Boolean.class) || returnType.equals(boolean.class)) return prop.getBoolean();
if (returnType.equals(Long.class) || returnType.equals(long.class)) return prop.getLong();
if (returnType.equals(Integer.class) || returnType.equals(int.class)) return prop.getLong();
if (returnType.isArray()) {
if (prop.getType()==PropertyType.BINARY) {
byte[] bytes = new byte[32000];
try (InputStream stream = prop.getBinary().getStream()){
stream.read(bytes);
}
return bytes;
} else {
Object[] ret= getArrayValue(prop);
return Arrays.copyOf(ret, ret.length, returnType);
}
}
throw new Exception(String.format("class %s not recognized",returnType.getName()));
}
@SuppressWarnings({ "rawtypes" })
private static Value getObjectValue(Class returnType, Object value) throws Exception{
if (returnType.equals(String.class)) return new StringValue((String) value);
if (returnType.isEnum()) return new StringValue(((Enum) value).toString());
if (returnType.equals(Calendar.class)) return new DateValue((Calendar) value);
if (returnType.equals(Boolean.class) || returnType.equals(boolean.class)) return new BooleanValue((Boolean) value);
if (returnType.equals(Long.class) || returnType.equals(long.class)) return new LongValue((Long) value);
if (returnType.equals(Integer.class) || returnType.equals(int.class)) return new LongValue((Long) value);
if (returnType.isArray()) {
if (returnType.getComponentType().equals(Byte.class)
|| returnType.getComponentType().equals(byte.class))
return new BinaryValue((byte[]) value);
}
throw new Exception(String.format("class %s not recognized",returnType.getName()));
}
private static Object[] getArrayValue(Property prop) throws Exception{
Object[] values = new Object[prop.getValues().length];
int i = 0;
for (Value value : prop.getValues())
values[i++] = getSingleValue(value);
return values;
}
private static Object getPropertyValue(Property prop) throws Exception{
if (prop.isMultiple()){
Object[] values = new Object[prop.getValues().length];
int i = 0;
for (Value value : prop.getValues())
values[i++] = getSingleValue(value);
return values;
} else
return getSingleValue(prop.getValue());
}
private static Object getSingleValue(Value value) throws Exception{
switch (value.getType()) {
case PropertyType.DATE:
return value.getDate();
case PropertyType.BOOLEAN:
return value.getBoolean();
case PropertyType.LONG:
return value.getDate();
default:
return value.getString();
}
}
private static Set<Field> retrieveAllFields(Class<?> clazz){
Set<Field> fields = new HashSet<Field>();
Class<?> currentClass = clazz;
do{
List<Field> fieldsFound = Arrays.asList(currentClass.getDeclaredFields());
fields.addAll(fieldsFound);
}while ((currentClass =currentClass.getSuperclass())!=null);
return fields;
}
public static <T extends Item> Node createNodeFromItem(Session session, Node parentNode, T item){
try {
//TODO: must understand this place is for name or title
String primaryType= classHandler.getNodeType(item.getClass());
Node newNode = parentNode.addNode(item.getTitle(), primaryType);
//newNode.setPrimaryType(primaryType);
for (Field field : retrieveAllFields(item.getClass())){
if (field.isAnnotationPresent(Attribute.class)){
Attribute attribute = field.getAnnotation(Attribute.class);
field.setAccessible(true);
try{
//Class<?> returnType = field.getType();
newNode.setProperty(attribute.value(), getObjectValue(field.getType(), field.get(item)));
} catch (Exception e ) {
logger.warn("error setting value for attribute "+attribute.value(),e);
}
} else if (field.isAnnotationPresent(NodeAttribute.class)){
NodeAttribute nodeAttribute = field.getAnnotation(NodeAttribute.class);
if (nodeAttribute.isReadOnly()) continue;
String nodeName = nodeAttribute.value();
logger.debug("retrieving field node "+field.getName());
field.setAccessible(true);
try{
iterateItemNodeAttributeFields(field.get(item), newNode, nodeName);
} catch (Exception e ) {
logger.warn("error setting value",e);
}
}
}
return newNode;
} catch (RepositoryException e) {
logger.error("error writing repository",e);
throw new RuntimeException(e);
}
}
private static void iterateItemNodeAttributeFields(Object object, Node parentNode, String nodeName) throws Exception{
AttributeRootNode attributeRootNode = object.getClass().getAnnotation(AttributeRootNode.class);
Node newNode = parentNode.addNode(nodeName, attributeRootNode.value());
//newNode.setPrimaryType(attributeRootNode.value());
for (Field field : retrieveAllFields(object.getClass())){
if (field.isAnnotationPresent(Attribute.class)){
Attribute attribute = field.getAnnotation(Attribute.class);
field.setAccessible(true);
try{
@SuppressWarnings("rawtypes")
Class returnType = field.getType();
newNode.setProperty(attribute.value(), getObjectValue(returnType, field.get(object)));
} catch (Exception e ) {
logger.warn("error setting value",e);
}
} else if (field.isAnnotationPresent(MapAttribute.class)){
//logger.debug("found field {} of type annotated as MapAttribute in class {}", field.getName(), clazz.getName());
field.setAccessible(true);
Map<String, Object> mapToset = (Map<String, Object>)field.get(object);
for (Entry<String, Object> entry : mapToset.entrySet())
try{
newNode.setProperty(entry.getKey(), getObjectValue(entry.getValue().getClass(), entry.getValue()));
} catch (Exception e ) {
logger.warn("error setting value",e);
}
} else if (field.isAnnotationPresent(ListNodes.class)){
logger.debug("found field {} of type annotated as ListNodes in class {} on node {}", field.getName(), object.getClass().getName(), newNode.getName());
field.setAccessible(true);
List<Object> toSetList = (List<Object>) field.get(object);
int i = 0;
for (Object obj: toSetList){
logger.debug("the current node {} has a list",newNode.getName());
iterateItemNodeAttributeFields(obj,newNode, field.getName()+(i++));
}
}
}
}
}

@ -0,0 +1,37 @@
package org.gcube.data.access.storagehub.handlers;
import javax.inject.Singleton;
import javax.jcr.Node;
import javax.jcr.Session;
import javax.jcr.version.Version;
import javax.jcr.version.VersionManager;
import org.apache.jackrabbit.JcrConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class VersionHandler {
private static final Logger logger = LoggerFactory.getLogger(VersionHandler.class);
public void makeVersionableContent(Node node, Session session){
try {
Node contentNode = node.getNode("jcr:content");
contentNode.addMixin(JcrConstants.MIX_VERSIONABLE);
}catch(Exception e ) {
logger.warn("cannot create versioned content node",e);
}
}
public void checkinContentNode(Node node, Session session){
try {
Node contentNode = node.getNode("jcr:content");
VersionManager versionManager = session.getWorkspace().getVersionManager();
Version version = versionManager.checkin(contentNode.getPath());
}catch(Exception e ) {
logger.warn("cannotcheckinNode content node",e);
}
}
}

@ -0,0 +1,18 @@
package org.gcube.data.access.storagehub.handlers.content;
import java.io.InputStream;
import java.util.List;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.nodes.Content;
public interface ContentHandler {
void initiliseSpecificContent(InputStream is) throws Exception;
Content getContent();
AbstractFileItem buildItem(String name, String description, String login);
}

@ -0,0 +1,49 @@
package org.gcube.data.access.storagehub.handlers.content;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
import javax.inject.Singleton;
import org.gcube.common.storagehub.model.annotations.MimeTypeHandler;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class ContentHandlerFactory {
private static Logger logger = LoggerFactory.getLogger(ContentHandlerFactory.class);
private Reflections reflection = new Reflections();
private static HashMap<String, Class<? extends ContentHandler>> handlerMap = new HashMap<String, Class<? extends ContentHandler>>();
private Class<? extends ContentHandler> defaultHandler = GenericFileHandler.class;
@SuppressWarnings("unchecked")
public ContentHandlerFactory() {
Set<Class<?>> classesAnnotated = reflection.getTypesAnnotatedWith(MimeTypeHandler.class);
for (Class<?> clazz: classesAnnotated ){
if (ContentHandler.class.isAssignableFrom(clazz)) {
logger.debug("searching for mimetypes {} with values {}",clazz.getName(), Arrays.toString(clazz.getAnnotation(MimeTypeHandler.class).value()));
for (String value: clazz.getAnnotation(MimeTypeHandler.class).value()){
logger.debug("value for class {} is {}",clazz.getName(), value);
handlerMap.put(value, (Class<? extends ContentHandler>) clazz);
}
}
}
}
public ContentHandler create(String mimetype) throws Exception{
Class<? extends ContentHandler> handlerClass = handlerMap.get(mimetype);
if (handlerClass!=null)
return handlerClass.newInstance();
else
return defaultHandler.newInstance();
}
}

@ -0,0 +1,43 @@
package org.gcube.data.access.storagehub.handlers.content;
import java.io.InputStream;
import java.util.Calendar;
import org.gcube.common.storagehub.model.items.GenericFileItem;
import org.gcube.common.storagehub.model.items.nodes.Content;
import org.gcube.common.storagehub.model.types.ItemAction;
public class GenericFileHandler implements ContentHandler{
Content content = new Content();
@Override
public void initiliseSpecificContent(InputStream is) throws Exception {}
@Override
public Content getContent() {
return content;
}
@Override
public GenericFileItem buildItem(String name, String description, String login) {
GenericFileItem item = new GenericFileItem();
Calendar now = Calendar.getInstance();
item.setName(name);
item.setTitle(name);
item.setDescription(description);
//item.setCreationTime(now);
item.setHidden(false);
item.setLastAction(ItemAction.CREATED);
item.setLastModificationTime(now);
item.setLastModifiedBy(login);
item.setOwner(login);
item.setContent(this.content);
return item;
}
}

@ -0,0 +1,136 @@
package org.gcube.data.access.storagehub.handlers.content;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Base64;
import java.util.Calendar;
import javax.imageio.ImageIO;
import org.gcube.common.storagehub.model.annotations.MimeTypeHandler;
import org.gcube.common.storagehub.model.items.ImageFile;
import org.gcube.common.storagehub.model.items.nodes.ImageContent;
import org.gcube.common.storagehub.model.types.ItemAction;
import ij.ImagePlus;
import ij.io.FileSaver;
import ij.process.ImageProcessor;
@MimeTypeHandler({"image/gif", "image/jpeg","image/png","image/svg+xml"})
public class ImageHandler implements ContentHandler{
private static final int THUMB_MAX_DIM = 50;
private ImageContent content = new ImageContent();
@Override
public void initiliseSpecificContent(InputStream is) throws Exception {
BufferedImage buf = ImageIO.read(is);
content.setWidth(Long.valueOf(buf.getWidth()));
content.setHeight(Long.valueOf(buf.getHeight()));
ImagePlus image = new ImagePlus("thumbnail", buf);
int thumbSize[] = getThumbnailDimension(buf.getWidth(), buf.getHeight());
try(ByteArrayOutputStream baos = new ByteArrayOutputStream(); InputStream thumbstream = getThumbnailAsPng(image, thumbSize[0], thumbSize[1])){
byte[] imgbuf = new byte[1024];
int read = -1;
while ((read=thumbstream.read(imgbuf))!=-1)
baos.write(imgbuf, 0, read);
content.setThumbnailHeight(Long.valueOf(thumbSize[1]));
content.setThumbnailWidth(Long.valueOf(thumbSize[0]));
content.setThumbnailData(Base64.getEncoder().encode(baos.toByteArray()));
} catch (Exception e) {
// TODO: handle exception
}
}
@Override
public ImageContent getContent() {
return content;
}
private int[] getThumbnailDimension(int original_width, int original_height) {
int new_width = 0;
int new_height = 0;
if ((original_width < THUMB_MAX_DIM) && (original_height< THUMB_MAX_DIM)){
new_width = original_width;
new_height = original_height;
}
if (original_width > THUMB_MAX_DIM) {
new_width = THUMB_MAX_DIM;
new_height = (new_width * original_height) / original_width;
}
if (original_width < THUMB_MAX_DIM) {
new_width = THUMB_MAX_DIM;
new_height = (new_width * original_height) / original_width;
}
if (new_height > THUMB_MAX_DIM) {
new_height = THUMB_MAX_DIM;
new_width = (new_height * original_width) / original_height;
}
if (new_width > THUMB_MAX_DIM) {
new_width = THUMB_MAX_DIM;
new_height = (new_width * original_height) / original_width;
}
int[] dimension = {new_width, new_height};
return dimension;
}
private InputStream getThumbnailAsPng(ImagePlus img, int thumbWidth,
int thumbHeight) throws IOException {
InputStream stream = null;
ImageProcessor processor = img.getProcessor();
try{
Image thumb = processor.resize(thumbWidth, thumbHeight).createImage();
thumb = thumb.getScaledInstance(thumbWidth,thumbHeight,Image.SCALE_SMOOTH);
FileSaver fs = new FileSaver(new ImagePlus("",thumb));
File tmpThumbFile = File.createTempFile("THUMB", "TMP");
tmpThumbFile.deleteOnExit();
fs.saveAsPng(tmpThumbFile.getAbsolutePath());
stream = new FileInputStream(tmpThumbFile);
}catch (Exception e) {
throw new RuntimeException(e);
}
return stream;
}
@Override
public ImageFile buildItem(String name, String description, String login) {
ImageFile item = new ImageFile();
Calendar now = Calendar.getInstance();
item.setName(name);
item.setTitle(name);
item.setDescription(description);
//item.setCreationTime(now);
item.setHidden(false);
item.setLastAction(ItemAction.CREATED);
item.setLastModificationTime(now);
item.setLastModifiedBy(login);
item.setOwner(login);
item.setContent(this.content);
return item;
}
}

@ -0,0 +1,59 @@
package org.gcube.data.access.storagehub.handlers.content;
import java.io.InputStream;
import java.util.Calendar;
import java.util.HashMap;
import org.gcube.common.storagehub.model.annotations.MimeTypeHandler;
import org.gcube.common.storagehub.model.items.PDFFileItem;
import org.gcube.common.storagehub.model.items.nodes.PDFContent;
import org.gcube.common.storagehub.model.types.ItemAction;
import com.itextpdf.text.pdf.PdfReader;
@MimeTypeHandler("application/pdf")
public class PdfHandler implements ContentHandler {
public static final String NUMBER_OF_PAGES = "xmpTPg:NPages";
public static final String PRODUCER = "producer";
public static final String VERSION = "version";
public static final String AUTHOR = "Author";
public static final String TITLE = "dc:title";
PDFContent content = new PDFContent();
@Override
public void initiliseSpecificContent(InputStream is) throws Exception {
PdfReader reader = new PdfReader(is);
content.setNumberOfPages(Long.valueOf(reader.getNumberOfPages()));
content.setVersion(String.valueOf(reader.getPdfVersion()));
HashMap<String, String> fileInfo = reader.getInfo();
content.setAuthor(fileInfo.containsKey(AUTHOR)?fileInfo.get(AUTHOR):"n/a");
content.setProducer(fileInfo.containsKey(PRODUCER)?fileInfo.get(PRODUCER):"n/a");
content.setTitle(fileInfo.containsKey(TITLE)?fileInfo.get(TITLE):"n/a");
}
@Override
public PDFContent getContent() {
return content;
}
public PDFFileItem buildItem(String name, String description, String login) {
PDFFileItem item = new PDFFileItem();
Calendar now = Calendar.getInstance();
item.setName(name);
item.setTitle(name);
item.setDescription(description);
//item.setCreationTime(now);
item.setHidden(false);
item.setLastAction(ItemAction.CREATED);
item.setLastModificationTime(now);
item.setLastModifiedBy(login);
item.setOwner(login);
item.setContent(this.content);
return item;
}
}

@ -0,0 +1,15 @@
package org.gcube.data.access.storagehub.query.sql2.evaluators;
import javax.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
@Singleton
public abstract class Evaluator<T extends Expression<?>> {
public abstract Class<T> getType();
public abstract String evaluate(T expr, Iterable<Evaluator<Expression<?>>> evaluators);
}

@ -0,0 +1,36 @@
package org.gcube.data.access.storagehub.query.sql2.evaluators;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
@Singleton
public class Evaluators {
public static Evaluator<Expression<?>> getEvaluator(Class<?> type, Iterable<Evaluator<Expression<?>>> evaluators){
for (Evaluator<Expression<?>> eval: evaluators) {
if (eval.getType().equals(type)) return eval;
}
throw new IllegalStateException("evaluator not found for class "+type.getName());
}
@Inject
Instance<Evaluator<?>> evaluators;
public String evaluate(Expression<?> expression) {
for (Evaluator eval: evaluators) {
if (eval.getType().equals(expression.getClass()))
return eval.evaluate(expression, evaluators);
}
throw new IllegalStateException("Evaluator not found for expression type "+expression.getClass());
}
public Instance<Evaluator<?>> getEvaluators() {
return evaluators;
}
}

@ -0,0 +1,37 @@
package org.gcube.data.access.storagehub.query.sql2.evaluators.date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.TimeZone;
import javax.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.date.Before;
import org.gcube.data.access.storagehub.query.sql2.evaluators.Evaluator;
@Singleton
public class BeforeEvaluator extends Evaluator<Before> {
@Override
public String evaluate(Before expr, Iterable<Evaluator<Expression<?>>> evaluators) {
TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
df.setTimeZone(tz);
return String.format("node.[%s] < CAST('%s' AS DATE)", expr.getSearchableField().getName(), df.format(expr.getValue().getTime()));
}
public Evaluator<Expression<?>> getEvaluator(Class<?> type, List<Evaluator<Expression<?>>> evaluators){
for (Evaluator<Expression<?>> eval: evaluators) {
if (eval.getType().equals(type)) return eval;
}
throw new IllegalStateException("evaluator not found for class "+type.getName());
}
@Override
public Class<Before> getType() {
return Before.class;
}
}

@ -0,0 +1,33 @@
package org.gcube.data.access.storagehub.query.sql2.evaluators.logical;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.logical.And;
import org.gcube.data.access.storagehub.query.sql2.evaluators.Evaluator;
import org.gcube.data.access.storagehub.query.sql2.evaluators.Evaluators;
@Singleton
public class AndEvaluator extends Evaluator<And> {
@Override
public String evaluate(And expr, Iterable<Evaluator<Expression<?>>> evaluators) {
List<String> evaluated = new ArrayList<>();
for (Expression<?> subExpression :expr.getExpressions()) {
Evaluator<Expression<?>> eval = Evaluators.getEvaluator(subExpression.getClass(), evaluators);
evaluated.add(eval.evaluate(subExpression, evaluators));
}
return "("+evaluated.stream().map(Object::toString).collect(Collectors.joining(" and ")).toString()+")";
}
@Override
public Class<And> getType() {
return And.class;
}
}

@ -0,0 +1,24 @@
package org.gcube.data.access.storagehub.query.sql2.evaluators.logical;
import javax.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.logical.ISDescendant;
import org.gcube.data.access.storagehub.query.sql2.evaluators.Evaluator;
@Singleton
public class ISDescendantEvaluator extends Evaluator<ISDescendant> {
@Override
public String evaluate(ISDescendant expr, Iterable<Evaluator<Expression<?>>> evaluators) {
return String.format("ISDESCENDANTNODE( node , [%s])", expr.getPath().toPath());
}
@Override
public Class<ISDescendant> getType() {
return ISDescendant.class;
}
}

@ -0,0 +1,35 @@
package org.gcube.data.access.storagehub.query.sql2.evaluators.logical;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.logical.Or;
import org.gcube.data.access.storagehub.query.sql2.evaluators.Evaluator;
import org.gcube.data.access.storagehub.query.sql2.evaluators.Evaluators;
@Singleton
public class OrEvaluator extends Evaluator<Or> {
@Override
public String evaluate(Or expr, Iterable<Evaluator<Expression<?>>> evaluators) {
List<String> evaluated = new ArrayList<>();
for (Expression<?> subExpression :expr.getExpressions()) {
Evaluator<Expression<?>> eval = Evaluators.getEvaluator(subExpression.getClass(), evaluators);
evaluated.add(eval.evaluate(subExpression, evaluators));
}
return "("+evaluated.stream().map(Object::toString).collect(Collectors.joining(" or ")).toString()+")";
}
@Override
public Class<Or> getType() {
return Or.class;
}
}

@ -0,0 +1,31 @@
package org.gcube.data.access.storagehub.query.sql2.evaluators.text;
import javax.inject.Singleton;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.text.Contains;
import org.gcube.data.access.storagehub.query.sql2.evaluators.Evaluator;
@Singleton
public class ContainsEvaluator extends Evaluator<Contains> {
@Override
public String evaluate(Contains expr, Iterable<Evaluator<Expression<?>>> evaluators) {
return String.format("node.[%s] LIKE '%%%s%%'", expr.getSearchableField().getName(), expr.getValue());
}
public Evaluator<Expression<?>> getEvaluator(Class<?> type, Iterable<Evaluator<Expression<?>>> evaluators){
for (Evaluator<Expression<?>> eval: evaluators) {
if (eval.getType().equals(type)) return eval;
}
throw new IllegalStateException("evaluator not found for class "+type.getName());
}
@Override
public Class<Contains> getType() {
return Contains.class;
}
}

@ -0,0 +1,267 @@
package org.gcube.data.access.storagehub.services;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.detect.Detector;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.CalledMethodProvider;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.service.ItemWrapper;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.MetaInfo;
import org.gcube.data.access.storagehub.MultipleOutputStream;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.handlers.ItemHandler;
import org.gcube.data.access.storagehub.handlers.VersionHandler;
import org.gcube.data.access.storagehub.handlers.content.ContentHandler;
import org.gcube.data.access.storagehub.handlers.content.ContentHandlerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Path("item")
public class ItemsCreator {
private static final Logger log = LoggerFactory.getLogger(ItemsCreator.class);
private static ExecutorService executor = Executors.newFixedThreadPool(100);
@Context ServletContext context;
@Inject
RepositoryInitializer repository;
@Inject
ContentHandlerFactory contenthandlerFactory;
@Inject
VersionHandler versionHandler;
@POST
@Path("/{id}/create/{type:(?!FILE)[^/?$]*}")
public Response createItem(@Context UriInfo uriInfo, @PathParam("id") String id, @PathParam("type") String type){
log.info("create generic item called");
Session ses = null;
Item destinationItem = null;
try{
final String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
//TODO check if it is possible to change all the ACL on a workspace
ses = repository.getRepository().login(new SimpleCredentials(context.getInitParameter(Constants.ADMIN_PARAM_NAME),context.getInitParameter(Constants.ADMIN_PARAM_PWD).toCharArray()));
//validate input parameters for Item Type
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
Node destination = ses.getNodeByIdentifier(id);
destinationItem = ItemHandler.getItem(destination,Arrays.asList("hl:accounting","jcr:content"));
if (!(destinationItem instanceof FolderItem)) throw new Exception("an Item must be copyed to another directory");
//TODO: write control
if (!destinationItem.getOwner().equals(login)){
/*AccessControlManager accessControlManager = ses.getAccessControlManager();
boolean canWrite = accessControlManager.hasPrivileges(path, new Privilege[] {
accessControlManager.privilegeFromName(Privilege.JCR_ADD_CHILD_NODES)});*/
//if (!canWrite)
throw new IllegalAccessException("Insufficent Provileges to write in "+destinationItem.getPath());
}
//ses.getWorkspace().getLockManager().lock(destinationItem.getPath(), true, true, 0,login);
//TODO for now only owner of the destination folder can move file
ses.save();
}catch(Exception e){
log.error("error creating item", e);
return Response.serverError().build();
} finally{
if (ses!=null){
if (destinationItem!=null)
try {
ses.getWorkspace().getLockManager().unlock(destinationItem.getPath());
} catch (Throwable t){
log.warn("error unlocking {}", destinationItem.getPath(), t);
}
ses.logout();
}
}
return Response.ok().build();
}
@POST
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
@Produces(MediaType.APPLICATION_JSON)
@Path("/{id}/create/FILE")
public Response createFileItem(InputStream stream , @PathParam("id") String id,
@QueryParam("name") String name, @QueryParam("description") String description){
CalledMethodProvider.instance.set("createFileItem");
log.info("create file called");
Session ses = null;
Item destinationItem = null;
try{
final String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
//TODO check if it is possible to change all the ACL on a workspace
ses = repository.getRepository().login(new SimpleCredentials(context.getInitParameter(Constants.ADMIN_PARAM_NAME),context.getInitParameter(Constants.ADMIN_PARAM_PWD).toCharArray()));
//validate input parameters for Item Type
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
Node destination = ses.getNodeByIdentifier(id);
destinationItem = ItemHandler.getItem(destination,Arrays.asList("hl:accounting","jcr:content"));
log.debug("destination item path is {}",destinationItem.getPath());
if (!(destinationItem instanceof FolderItem)) throw new Exception("an Item must be copyed to another directory");
//TODO: write control
if (!destinationItem.getOwner().equals(login)){
/*AccessControlManager accessControlManager = ses.getAccessControlManager();
boolean canWrite = accessControlManager.hasPrivileges(path, new Privilege[] {
accessControlManager.privilegeFromName(Privilege.JCR_ADD_CHILD_NODES)});*/
//if (!canWrite)
throw new IllegalAccessException("Insufficent Provileges to write in "+destinationItem.getPath());
}
ses.getWorkspace().getLockManager().lock(destinationItem.getPath(), true, true, 0,login);
ContentHandler handler = getContentHandler(stream , name, destinationItem.getPath());
AbstractFileItem item =handler.buildItem(name, description, login);
log.debug("item prepared, fulfilling content");
log.debug("content prepared");
Node newNode = ItemHandler.createNodeFromItem(ses, destination, item);
versionHandler.makeVersionableContent(newNode, ses);
ses.save();
versionHandler.checkinContentNode(newNode, ses);;
log.info("item correctly created");
return Response.ok(new ItemWrapper<>(item)).build();
}catch(Throwable e){
log.error("error creating item", e);
return Response.serverError().build();
} finally{
if (ses!=null){
if (destinationItem!=null)
try {
ses.getWorkspace().getLockManager().unlock(destinationItem.getPath());
} catch (Throwable t){
log.warn("error unlocking {}", destinationItem.getPath(), t);
}
ses.logout();
}
}
}
private ContentHandler getContentHandler(InputStream stream , String name, String path) throws Exception {
final MultipleOutputStream mos = new MultipleOutputStream(stream, 2);
Callable<ContentHandler> mimeTypeDector = new Callable<ContentHandler>() {
@Override
public ContentHandler call() throws Exception {
ContentHandler handler =null;
try(BufferedInputStream is1 = new BufferedInputStream(mos.get(), 2048)){
org.apache.tika.mime.MediaType mediaType = null;
TikaConfig config = TikaConfig.getDefaultConfig();
Detector detector = config.getDetector();
TikaInputStream stream = TikaInputStream.get(is1);
Metadata metadata = new Metadata();
metadata.add(Metadata.RESOURCE_NAME_KEY, name);
mediaType = detector.detect(stream, metadata);
String mimeType = mediaType.getBaseType().toString();
handler = contenthandlerFactory.create(mimeType);
is1.reset();
handler.initiliseSpecificContent(is1);
handler.getContent().setMimeType(mimeType);
} catch (Throwable e) {
log.error("error retreiving content",e);
throw new RuntimeException(e);
}
return handler;
}
};
Callable<MetaInfo> uploader = new Callable<MetaInfo>() {
@Override
public MetaInfo call() throws Exception {
String remotePath= path+"/"+name;
String storageId = Utils.getStorageClient(AuthorizationProvider.instance.get().getClient().getId()).getClient().put(true).LFile(mos.get()).RFile(remotePath);
long size = Utils.getStorageClient(AuthorizationProvider.instance.get().getClient().getId()).getClient().getSize().RFileById(storageId);
MetaInfo info = new MetaInfo();
info.setSize(size);
info.setStorageId(storageId);
return info;
}
};
Future<ContentHandler> detectorF = executor.submit(mimeTypeDector);
Future<MetaInfo> uploaderF = executor.submit(uploader);
mos.startWriting();
ContentHandler handler = detectorF.get();
handler.getContent().setData("jcr:content");
handler.getContent().setStorageId(uploaderF.get().getStorageId());
handler.getContent().setSize(uploaderF.get().getSize());
return handler;
}
/*
private boolean hasSharedChildren(FolderItem folder, Session session) throws Exception{
Node currentNode = session.getNodeByIdentifier(folder.getId());
for (Item item : Utils.getItemList(currentNode,Arrays.asList("hl:accounting","jcr:content"), null)){
if (item instanceof FolderItem)
return (item instanceof SharedFolder) || hasSharedChildren((FolderItem)item, session);
}
return false;
}*/
}

@ -0,0 +1,321 @@
package org.gcube.data.access.storagehub.services;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
import java.util.zip.Deflater;
import java.util.zip.ZipOutputStream;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.servlet.ServletContext;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.storagehub.model.Paths;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.SharedFolder;
import org.gcube.common.storagehub.model.service.ItemList;
import org.gcube.common.storagehub.model.service.ItemWrapper;
import org.gcube.data.access.storagehub.AuthorizationChecker;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.Range;
import org.gcube.data.access.storagehub.SingleFileStreamingOutput;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.handlers.ItemHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Path("item")
public class ItemsManager {
private static final Logger log = LoggerFactory.getLogger(ItemsManager.class);
@Inject
RepositoryInitializer repository;
@Inject
AccountingHandler accountingHandler;
@RequestScoped
@PathParam("id")
String id;
@Context
ServletContext context;
@Inject
AuthorizationChecker authChecker;
@GET()
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getById(@QueryParam("exclude") List<String> excludes){
Session ses = null;
Item toReturn = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
log.info("excludes is {}",excludes);
toReturn = ItemHandler.getItem(ses.getNodeByIdentifier(id), excludes);
}catch(Throwable e){
log.error("error reading the node children of {}",id,e);
throw new WebApplicationException(e);
}finally{
if (ses!=null)
ses.logout();
}
return new ItemWrapper<Item>(toReturn);
}
@GET
@Path("{id}/children/count")
@Produces(MediaType.APPLICATION_JSON)
public Long countById(@QueryParam("showHidden") Boolean showHidden, @QueryParam("exclude") List<String> excludes){
Session ses = null;
Long toReturn = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
log.info("excludes is {}",excludes);
toReturn = Utils.getItemCount(ses.getNodeByIdentifier(id), showHidden==null?false:showHidden);
}catch(Throwable e){
log.error("error reading the node children of {}",id,e);
throw new WebApplicationException(e);
}finally{
if (ses!=null)
ses.logout();
}
return toReturn ;
}
@GET
@Path("{id}/children")
@Produces(MediaType.APPLICATION_JSON)
public ItemList listById(@QueryParam("showHidden") Boolean showHidden, @QueryParam("exclude") List<String> excludes){
Session ses = null;
List<? extends Item> toReturn = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
log.info("excludes is {}",excludes);
toReturn = Utils.getItemList(ses.getNodeByIdentifier(id), excludes, null, showHidden==null?false:showHidden);
}catch(Throwable e){
log.error("error reading the node children of {}",id,e);
throw new WebApplicationException(e);
}finally{
if (ses!=null)
ses.logout();
}
return new ItemList(toReturn);
}
@GET
@Path("{id}/children/paged")
@Produces(MediaType.APPLICATION_JSON)
public ItemList listByIdPaged(@QueryParam("showHidden") Boolean showHidden, @QueryParam("start") Integer start, @QueryParam("limit") Integer limit, @QueryParam("exclude") List<String> excludes){
Session ses = null;
List<? extends Item> toReturn = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
log.info("excludes is {}",excludes);
toReturn = Utils.getItemList(ses.getNodeByIdentifier(id), excludes, new Range(start, limit),showHidden==null?false:showHidden);
}catch(Throwable e){
log.error("error reading the node children of {}",id,e);
throw new WebApplicationException(e);
}finally{
if (ses!=null)
ses.logout();
}
return new ItemList(toReturn);
}
@GET
@Path("{id}/publiclink")
public URL getPubliclink() {
//TODO: check who can call this method
Session ses = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
String url = Utils.getStorageClient(login).getClient().getHttpsUrl().RFileById(id);
return new URL(url);
}catch(Throwable e){
log.error("error reading the node children of {}",id,e);
throw new WebApplicationException(e);
}finally{
if (ses!=null)
ses.logout();
}
}
@GET
@Path("{id}/download")
public Response download(){
Session ses = null;
try{
final String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(context.getInitParameter(Constants.ADMIN_PARAM_NAME),context.getInitParameter(Constants.ADMIN_PARAM_PWD).toCharArray()));
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
final Node node = ses.getNodeByIdentifier(id);
authChecker.checkReadAuthorizationControl(ses, id);
final Item item = ItemHandler.getItem(node, null);
if (item instanceof AbstractFileItem){
AbstractFileItem fileItem =(AbstractFileItem) item;
final InputStream streamToWrite = Utils.getStorageClient(login).getClient().get().RFileAsInputStream(fileItem.getContent().getStorageId());
accountingHandler.createReadObj(fileItem.getTitle(), ses, node, true);
StreamingOutput so = new SingleFileStreamingOutput(streamToWrite);
return Response
.ok(so)
.header("content-disposition","attachment; filename = "+fileItem.getName())
.header("Content-Length", fileItem.getContent().getSize())
.build();
} else if (item instanceof FolderItem){
try {
final Deque<Item> allNodes = Utils.getAllNodesForZip((FolderItem)item, ses, accountingHandler);
final org.gcube.common.storagehub.model.Path originalPath = Paths.getPath(item.getPath());
StreamingOutput so = new StreamingOutput() {
@Override
public void write(OutputStream os) {
try(ZipOutputStream zos = new ZipOutputStream(os)){
long start = System.currentTimeMillis();
zos.setLevel(Deflater.BEST_COMPRESSION);
log.debug("writing StreamOutput");
Utils.zipNode(zos, allNodes, login, originalPath);
log.debug("StreamOutput written in {}",(System.currentTimeMillis()-start));
} catch (Exception e) {
log.error("error writing stream",e);
}
}
};
return Response
.ok(so)
.header("content-disposition","attachment; filename = directory.zip")
.header("Content-Length", -1l)
.build();
}finally {
if (ses!=null) ses.save();
}
} else throw new Exception("item type not supported for download: "+item.getClass());
}catch(Exception e ){
log.error("error downloading item content",e);
throw new WebApplicationException(e);
} finally{
if (ses!=null) ses.logout();
}
}
@PUT
@Path("{id}/move")
public Response move(@QueryParam("newpath") String path, @PathParam("id") String identifier){
Session ses = null;
try{
final String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
//ses = RepositoryInitializer.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
//TODO check if it is possible to change all the ACL on a workspace
ses = repository.getRepository().login(new SimpleCredentials(context.getInitParameter(Constants.ADMIN_PARAM_NAME),context.getInitParameter(Constants.ADMIN_PARAM_PWD).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
final Node nodeToMove = ses.getNodeByIdentifier(identifier);
final Node destination = ses.getNode(path);
Item destinationItem = ItemHandler.getItem(destination,null);
//TODO for now only owner of the destination folder can move file
if (!destinationItem.getOwner().equals(login)){
/*AccessControlManager accessControlManager = ses.getAccessControlManager();
boolean canWrite = accessControlManager.hasPrivileges(path, new Privilege[] {
accessControlManager.privilegeFromName(Privilege.JCR_ADD_CHILD_NODES)});*/
//if (!canWrite)
throw new IllegalAccessException("Insufficent Provileges to write in "+path);
}
final Item item = ItemHandler.getItem(nodeToMove, null);
if (item instanceof SharedFolder){
throw new Exception("shared folder cannot be moved");
}else if (item instanceof FolderItem){
if (hasSharedChildren((FolderItem) item, ses)) throw new Exception("folder item with shared children cannot be moved");
ses.getWorkspace().move(nodeToMove.getPath(), destination.getPath()+"/"+nodeToMove.getName());
}else {
item.setParentId(destinationItem.getId());
ses.getWorkspace().move(nodeToMove.getPath(), destination.getPath()+"/"+nodeToMove.getName());
}
ses.save();
}catch(Exception e){
log.error("error moving item with id {} in path {}",identifier, path,e);
throw new WebApplicationException(e);
} finally{
if (ses!=null) ses.logout();
}
return Response.ok().build();
}
private boolean hasSharedChildren(FolderItem item, Session session) throws Exception{
Node currentNode = session.getNodeByIdentifier(item.getId());
for (Item children : Utils.getItemList(currentNode,Arrays.asList("hl:accounting","jcr:content"), null, false)){
if (children instanceof FolderItem)
return (children instanceof SharedFolder) || hasSharedChildren((FolderItem)item, session);
}
return false;
}
}

@ -0,0 +1,8 @@
package org.gcube.data.access.storagehub.services;
import javax.jcr.Repository;
public interface RepositoryInitializer {
Repository getRepository();
}

@ -0,0 +1,379 @@
package org.gcube.data.access.storagehub.services;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.query.Query;
import javax.jcr.query.QueryResult;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.xml.ws.WebServiceException;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.common.scope.impl.ScopeBean.Type;
import org.gcube.common.storagehub.model.Paths;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.logical.And;
import org.gcube.common.storagehub.model.expressions.logical.ISDescendant;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.service.ItemList;
import org.gcube.common.storagehub.model.service.ItemWrapper;
import org.gcube.data.access.storagehub.Constants;
import org.gcube.data.access.storagehub.Range;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.handlers.ItemHandler;
import org.gcube.data.access.storagehub.query.sql2.evaluators.Evaluators;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
@Path("")
public class WorkspaceManager {
private static final Logger log = LoggerFactory.getLogger(WorkspaceManager.class);
@Inject
RepositoryInitializer repository;
@Inject
Evaluators evaluator;
@RequestScoped
@QueryParam("exclude")
private List<String> excludes = Collections.emptyList();
@Path("")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getWorkspace(){
Session ses = null;
org.gcube.common.storagehub.model.Path absolutePath = Utils.getHomePath();
Item toReturn = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
toReturn = ItemHandler.getItem(ses.getNode(absolutePath.toPath()), excludes);
}catch(Throwable e){
log.error("error reading the node children of {}",absolutePath,e);
}finally{
if (ses!=null)
ses.logout();
}
return new ItemWrapper<Item>(toReturn);
}
@Path("vrefolder")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getVreRootFolder(){
Session ses = null;
org.gcube.common.storagehub.model.Path vrePath = Paths.append(Utils.getHomePath(), Constants.VRE_FOLDER_PARENT_NAME);
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
ScopeBean bean = new ScopeBean(ScopeProvider.instance.get());
if (!bean.is(Type.VRE)) throw new Exception("the current scope is not a VRE");
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
String entireScopename= bean.toString().replaceAll("^/(.*)/?$", "$1").replaceAll("/", "-");
String query = String.format("SELECT * FROM [nthl:workspaceItem] As node WHERE node.[jcr:title] like '%s'", entireScopename);
Query jcrQuery = ses.getWorkspace().getQueryManager().createQuery(query, Constants.QUERY_LANGUAGE);
NodeIterator it = jcrQuery.execute().getNodes();
if (!it.hasNext()) throw new Exception("vre folder not found for context "+bean.toString());
Node folder = it.nextNode();
Item item = ItemHandler.getItem(folder, excludes);
return new ItemWrapper<Item>(item);
}catch(Throwable e){
log.error("error reading node {}",vrePath,e);
throw new WebApplicationException("error retrieving vre folder",e);
}finally{
if (ses!=null)
ses.logout();
}
}
@Path("trash")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getTrashRootFolder(){
Session ses = null;
org.gcube.common.storagehub.model.Path trashPath = Paths.append(Utils.getHomePath(), Constants.TRASH_ROOT_FOLDER_NAME);
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
Node folder = ses.getNode(trashPath.toPath());
Item item = ItemHandler.getItem(folder, excludes);
return new ItemWrapper<Item>(item);
}catch(Throwable e){
log.error("error reading the node {}",trashPath,e);
throw new WebApplicationException("error retrieving trash folder",e);
}finally{
if (ses!=null)
ses.logout();
}
}
@Path("vrefolders")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemList getVreFolders(){
Session ses = null;
org.gcube.common.storagehub.model.Path vrePath = Paths.append(Utils.getHomePath(), Constants.VRE_FOLDER_PARENT_NAME);
List<? extends Item> toReturn = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
toReturn = Utils.getItemList(ses.getNode(vrePath.toPath()) , excludes, null, false);
}catch(Throwable e){
log.error("error reading the node children of {}",vrePath,e);
}finally{
if (ses!=null)
ses.logout();
}
return new ItemList(toReturn);
}
@Path("vrefolders/paged")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemList getVreFoldersPaged(@QueryParam("start") Integer start, @QueryParam("limit") Integer limit){
Session ses = null;
org.gcube.common.storagehub.model.Path vrePath = Paths.append(Utils.getHomePath(), Constants.VRE_FOLDER_PARENT_NAME);
List<? extends Item> toReturn = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
toReturn = Utils.getItemList(ses.getNode(vrePath.toPath()) , excludes, new Range(start, limit), false);
}catch(Throwable e){
log.error("error reading the node children of {}",vrePath,e);
}finally{
if (ses!=null)
ses.logout();
}
return new ItemList(toReturn);
}
@Path("query")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemList searchItems(@QueryParam("n") String node, @QueryParam("e") String jsonExpr, @QueryParam("o") List<String> orderField, @QueryParam("l") Integer limit, @QueryParam("f") Integer offset){
Session ses = null;
List<? extends Item> toReturn = new ArrayList<>();
try{
ObjectMapper mapper = new ObjectMapper();
Expression<Boolean> expression = mapper.readValue(jsonExpr, Expression.class);
String stringExpression = evaluator.evaluate(new And(new ISDescendant(Utils.getHomePath()), expression));
//ADD ALSO LIMIT AND OFFSET
String orderBy = "";
if (orderField!=null && orderField.size()>0)
orderBy= String.format("ORDER BY %s", orderField.stream().collect(Collectors.joining(",")).toString());
String sql2Query = String.format("SELECT * FROM [%s] AS node WHERE %s %s ",node, stringExpression,orderBy);
log.info("query sent is {}",sql2Query);
String login = AuthorizationProvider.instance.get().getClient().getId();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
Query jcrQuery = ses.getWorkspace().getQueryManager().createQuery(sql2Query, Constants.QUERY_LANGUAGE);
if (limit!=null && limit!=-1 )
jcrQuery.setLimit(limit);
if (offset!=null && offset!=-1 )
jcrQuery.setOffset(offset);
QueryResult result = jcrQuery.execute();
NodeIterator it = result.getNodes();
while (it.hasNext())
toReturn.add(ItemHandler.getItem(it.nextNode(), excludes));
}catch(Throwable e){
log.error("error executing the query",e);
throw new WebServiceException("error executing the query", e);
}finally{
if (ses!=null)
ses.logout();
}
return new ItemList(toReturn);
}
/*
@POST
@Path("create")
@Consumes({MediaType.MULTIPART_FORM_DATA})
public Response create(@FormDataParam("item") ItemWrapper itemWrapper, @FormDataParam("file") InputStream stream , @FormDataParam("file") FormDataBodyPart fileDetail, @QueryParam("path") String path){
Session ses = null;
log.debug("method create called");
org.gcube.common.storagehub.model.Path absolutePath = Paths.append(Utils.getHomePath(), Paths.getPath(path));
try{
final String login = AuthorizationProvider.instance.get().getClient().getId();
//long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials("workspacerep.imarine","gcube2010*onan".toCharArray()));
log.debug("session retrieved");
ItemHandler handler = new ItemHandler();
Node parentNode = ses.getNode(absolutePath.toPath());
Item item = itemWrapper.getItem();
if (item instanceof AbstractFileItem){
if (stream==null)
throw new Exception("invalid item: file without an input stream is not accepted");
fulfillContent((AbstractFileItem)item, stream, fileDetail, absolutePath.toPath());
}
Calendar now = Calendar.getInstance();
item.setCreationTime(now);
item.setHidden(false);
item.setLastAction(ItemAction.CREATED);
item.setLastModificationTime(now);
item.setLastModifiedBy(login);
item.setOwner(login);
handler.createNodeFromItem(ses, parentNode, item, stream);
ses.save();
}catch(Throwable e){
log.error("error creating file",e);
return Response.serverError().build();
} finally{
if (ses!=null) ses.logout();
}
return Response.ok().build();
}
private void fulfillContent(AbstractFileItem item, InputStream stream , FormDataBodyPart fileDetail, String path) {
if (item instanceof GenericFileItem){
Content content = new Content();
String remotePath= path+"/"+fileDetail.getContentDisposition().getFileName();
content.setData("jcr:content");
content.setRemotePath(remotePath);
content.setSize(fileDetail.getContentDisposition().getSize());
content.setMimeType(fileDetail.getMediaType().toString());
String storageId = Utils.getStorageClient(AuthorizationProvider.instance.get().getClient().getId()).getClient().put(true).LFile(stream).RFile(remotePath);
content.setStorageId(storageId);
((GenericFileItem) item).setContent(content);
} else throw new RuntimeException("type file error");
}
@PUT
@Path("{id}/move")
public Response move(@QueryParam("path") String path, @PathParam("id") String identifier){
Session ses = null;
try{
final String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
//ses = RepositoryInitializer.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
//TODO check if it is possible to change all the ACL on a workspace
ses = repository.getRepository().login(new SimpleCredentials("workspacerep.imarine","gcube2010*onan".toCharArray()));
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
final Node nodeToMove = ses.getNodeByIdentifier(identifier);
final Node destination = ses.getNode(path);
Item destinationItem = ItemHandler.getItem(destination,null);
//TODO for now only owner of the destination folder can move file
if (!destinationItem.getOwner().equals(login)){
/*AccessControlManager accessControlManager = ses.getAccessControlManager();
boolean canWrite = accessControlManager.hasPrivileges(path, new Privilege[] {
accessControlManager.privilegeFromName(Privilege.JCR_ADD_CHILD_NODES)});*/
//if (!canWrite)
/*
throw new IllegalAccessException("Insufficent Provileges to write in "+path);
}
final Item item = ItemHandler.getItem(nodeToMove, null);
if (item instanceof SharedFolder){
throw new Exception("shared item cannot be moved");
}else if (item instanceof FolderItem){
if (hasSharedChildren((FolderItem) item, ses)) throw new Exception("folder item with shared children cannot be moved");
ses.getWorkspace().move(nodeToMove.getPath(), destination.getPath()+"/"+nodeToMove.getName());
}else {
item.setParentId(destinationItem.getId());
ses.getWorkspace().move(nodeToMove.getPath(), destination.getPath()+"/"+nodeToMove.getName());
}
ses.save();
}catch(Exception e){
log.error("error moving item with id {} in path {}",identifier, path,e);
return Response.serverError().build();
} finally{
if (ses!=null) ses.logout();
}
return Response.ok().build();
}
private boolean hasSharedChildren(FolderItem folder, Session session) throws Exception{
Node currentNode = session.getNodeByIdentifier(folder.getId());
for (Item item : Utils.getItemList(currentNode,null)){
if (item instanceof FolderItem)
return (item instanceof SharedFolder) || hasSharedChildren((FolderItem)item, session);
}
return false;
}
@PUT
@Path("{id}/rename")
public Response rename(@QueryParam("newname") String newName, @PathParam("id") String identifier){
Session ses = null;
try{
final String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
}catch(Exception e){
}
return Response.ok().build();
}
*/
}

@ -0,0 +1,118 @@
package org.gcube.data.access.storagehub.services;
import java.util.List;
import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.storagehub.model.Paths;
import org.gcube.common.storagehub.model.items.AbstractFileItem;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.items.SharedFolder;
import org.gcube.common.storagehub.model.types.PrimaryNodeType;
import org.gcube.data.access.storagehub.StorageFactory;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.handlers.ItemHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Path("modify")
public class WriteOperation {
private static final Logger log = LoggerFactory.getLogger(WriteOperation.class);
@Inject
RepositoryInitializer repository;
/*
@PUT
@Path("copy")
public String copy(@QueryParam("destinationPath") String destinationPath, @QueryParam("sourcePath") String origin){
Session ses = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
Node originNode = ses.getNode(origin);
Item originItem = ItemHandler.getItem(originNode, null);
Node destinationNode = ses.getNode(destinationPath);
Item destinationItem = ItemHandler.getItem(destinationNode, null);
if (!(destinationItem instanceof FolderItem)) throw new Exception("an Item must be copyed to another directory");
if (originItem instanceof SharedFolder) throw new Exception("trying to copy a sharedFolder into a normal folder");
ses.getWorkspace().getLockManager().lock(origin, true, true, 0,login);
ses.getWorkspace().getLockManager().lock(destinationPath, true, true, 0,login);
if (!destinationItem.getPrimaryType().equals(PrimaryNodeType.NT_WORKSPACE_FOLDER) ||
!destinationItem.getPrimaryType().equals(PrimaryNodeType.NT_WORKSPACE_SHARED_FOLDER))
throw new Exception("origin is not a folder");
ses.getWorkspace().getLockManager().lock(origin, true, true, Long.MAX_VALUE, login);
ses.getWorkspace().getLockManager().lock(destinationPath, false, true, Long.MAX_VALUE, login);
ses.getWorkspace().copy(origin, destinationPath);
org.gcube.common.storagehub.model.Path newNodePath = Paths.append(Paths.getPath(destinationPath), Paths.getPath(origin).getLastDirName());
if (originItem instanceof FolderItem ){
//copying a folder
StorageFactory.getGcubeStorage().copyDir().from(origin).to(destinationPath);
List<Item> items= Utils.getItemList(originNode,null, null);
for (Item item: items){
if (item instanceof FolderItem){
//TODO iterate on it recursively
} else if (item instanceof AbstractFileItem) {
String storageId = ((AbstractFileItem) item).getContent().getStorageId();
//String newStorageId = StorageFactory.getGcubeStorage().copyById(storageId);
//TODO set the new storageId into the item
} //else nothing to do
}
} else {
//copying item that is not a folder
}
ItemHandler handler = new ItemHandler();
//itera su i nodi e modifica solo quelli che non sono di tipo folder facendo la copy del content (con le nuovi api dello storage)
//e setta il nuovo id del content
//copy also the content of the directory
ses.save();
return destinationPath;
}catch(Exception e){
log.error("error copying {} to {}", origin, destinationPath);
return null;
} finally {
if (ses!=null){
try {
ses.getWorkspace().getLockManager().unlock(destinationPath);
} catch (Throwable t){
log.warn("error unlocking {}", destinationPath);
}
try {
ses.getWorkspace().getLockManager().unlock(origin);
} catch (Throwable t){
log.warn("error unlocking {}", origin);
}
ses.logout();
}
}
}
*/
}

@ -0,0 +1,5 @@
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">
</beans>

@ -0,0 +1,7 @@
<application mode='online'>
<name>StorageHub</name>
<group>DataAccess</group>
<version>1.0.0-SNAPSHOT</version>
<description>Storage Hub webapp</description>
<local-persistence location='target' />
</application>

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<context-param>
<param-name>admin-username</param-name>
<param-value>workspacerep.imarine</param-value>
</context-param>
<context-param>
<param-name>admin-pwd</param-name>
<param-value>gcube2010*onan</param-value>
</context-param>
<servlet>
<servlet-name>org.gcube.data.access.storagehub.StorageHub</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>org.gcube.data.access.storagehub.StorageHub</servlet-name>
<url-pattern>/workspace/*</url-pattern>
</servlet-mapping>
</web-app>

@ -0,0 +1,39 @@
package org.gcube.data.access.fs;
import java.util.Calendar;
import javax.inject.Inject;
import org.gcube.common.storagehub.model.expressions.Expression;
import org.gcube.common.storagehub.model.expressions.GenericSearchableItem;
import org.gcube.common.storagehub.model.expressions.date.Before;
import org.gcube.common.storagehub.model.expressions.logical.And;
import org.gcube.common.storagehub.model.expressions.text.Contains;
import org.gcube.data.access.storagehub.query.sql2.evaluators.Evaluators;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RunWith(WeldJunit4Runner.class)
public class Expressions {
private static Logger log = LoggerFactory.getLogger(Expression.class);
@Inject
Evaluators evaluators;
@Test
public void test() {
evaluators.getEvaluators().forEach(s-> System.out.println(s.getType().toString()));
Expression<Boolean> cont1 = new Contains(GenericSearchableItem.get().title, "Data");
Expression<Boolean> before = new Before(GenericSearchableItem.get().creationTime, Calendar.getInstance());
Expression<Boolean> andExpr = new And(cont1, before);
System.out.println(evaluators.evaluate(andExpr));
}
}

@ -0,0 +1,65 @@
package org.gcube.data.access.fs;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.nodetype.NodeType;
import org.gcube.common.storagehub.model.items.Item;
import org.gcube.common.storagehub.model.types.ItemAction;
import org.gcube.data.access.storagehub.handlers.ItemHandler;
import org.junit.Assert;
import org.junit.Test;
public class TestFields {
@Test
public void replace(){
System.out.println("/Home/Giancarlo".replaceAll("^/(.*)/?$", "$1").replaceAll("/", "-"));
}
@Test
public void iterateOverFields() throws Exception{
Property prop = mock(Property.class);
when(prop.getString()).thenReturn(ItemAction.UPDATED.name());
when(prop.getLong()).thenReturn(2l);
when(prop.getBoolean()).thenReturn(false);
Node parent = mock(Node.class);
NodeType parentType = mock(NodeType.class);
when(parentType.getName()).thenReturn("nthl:workspaceSharedItem");
when(parent.getPrimaryNodeType()).thenReturn(parentType);
when(parent.getName()).thenReturn("parent");
when(parent.getPath()).thenReturn("path");
when(parent.isLocked()).thenReturn(false);
when(parent.getParent()).thenReturn(null);
when(parent.getProperty(anyString())).thenReturn(prop);
when(parent.getNode(anyString())).thenReturn(parent);
Node node = mock(Node.class);
NodeType type = mock(NodeType.class);
when(type.getName()).thenReturn("nthl:externalImage");
when(node.getPrimaryNodeType()).thenReturn(type);
when(node.getName()).thenReturn("name");
when(node.getPath()).thenReturn("path");
when(node.isLocked()).thenReturn(false);
when(node.getParent()).thenReturn(parent);
when(node.getProperty(anyString())).thenReturn(prop);
when(node.getNode(anyString())).thenReturn(node);
Item item = ItemHandler.getItem(node, Arrays.asList("hl:accounting","jcr:content"));
Assert.assertTrue(item.isShared());
}
}

@ -0,0 +1,38 @@
package org.gcube.data.access.fs;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.ImageObserver;
import java.io.File;
import java.util.Base64;
import javax.imageio.ImageIO;
import org.junit.Test;
public class TestNode {
@Test
public void testShared() throws Exception{
BufferedImage buf = ImageIO.read(new File("/home/lucio/Downloads/djbattle.png"));
byte[] bigImageInByte = ((DataBufferByte) buf.getData().getDataBuffer()).getData();
System.out.println(new String(Base64.getEncoder().encode(bigImageInByte)));
/*
Image image = buf.getScaledInstance(64, 64, Image.SCALE_SMOOTH);
BufferedImage buffered = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_4BYTE_ABGR);
buffered.getGraphics().drawImage(image, 0, 0, null);
byte[] imageInByte = ((DataBufferByte) buffered.getData().getDataBuffer()).getData();
*/
/*buffered.getGraphics().drawImage(image, 0, 0 , null);
ImageIO.write(buffered, "png", buffer );
byte[] imageInByte = buffer.toByteArray();*/
}
}

@ -0,0 +1,27 @@
package org.gcube.data.access.fs;
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
public class WeldContext {
public static final WeldContext INSTANCE = new WeldContext();
private final Weld weld;
private final WeldContainer container;
private WeldContext() {
this.weld = new Weld();
this.container = weld.initialize();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
weld.shutdown();
}
});
}
public <T> T getBean(Class<T> type) {
return container.instance().select(type).get();
}
}

@ -0,0 +1,17 @@
package org.gcube.data.access.fs;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
public class WeldJunit4Runner extends BlockJUnit4ClassRunner {
public WeldJunit4Runner(Class<Object> clazz) throws InitializationError {
super(clazz);
}
@Override
protected Object createTest() {
final Class<?> test = getTestClass().getJavaClass();
return WeldContext.INSTANCE.getBean(test);
}
}

@ -0,0 +1,5 @@
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">
</beans>

@ -0,0 +1,12 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
</configuration>
Loading…
Cancel
Save