diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component
index ea3d26e..65eedd1 100644
--- a/.settings/org.eclipse.wst.common.component
+++ b/.settings/org.eclipse.wst.common.component
@@ -4,7 +4,6 @@
-
diff --git a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/StatisticsPanel.java b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/StatisticsPanel.java
index 38309d5..e310412 100644
--- a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/StatisticsPanel.java
+++ b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/StatisticsPanel.java
@@ -15,6 +15,7 @@ import org.gcube.portlet.user.userstatisticsportlet.client.resources.Images;
import org.gcube.portlet.user.userstatisticsportlet.client.ui.ActivityWidget;
import org.gcube.portlet.user.userstatisticsportlet.client.ui.StatisticWidget;
import org.gcube.portlet.user.userstatisticsportlet.shared.PostsStatsBean;
+import org.gcube.portlet.user.userstatisticsportlet.shared.QuotaInfo;
import org.gcube.portlet.user.userstatisticsportlet.shared.UserInformation;
import com.github.gwtbootstrap.client.ui.AlertBlock;
@@ -69,12 +70,14 @@ public class StatisticsPanel extends Composite {
private final static String ACTIVITY_LABEL = "Activity";
private final static String LIKES_COMMENTS_GOT_LABEL = "Got";
private final static String STORAGE_LABEL = "Space Used";
+ protected static final String QUOTA_LABEL = "Space Quota";
private final static String PROFILE_STRENGTH_LABEL = "Profile Strength";
private final static String SHOW_STATISTICS_OPTION_LABEL = "Show my statistics to VRE Members";
/**
* Some tooltips
*/
+ protected static final String TOOLTIP_QUOTA_SPACE = "Space used in the storage area is $USED of $ALLOWED";
private final static String TOOLTIP_ACTIVITY_ROOT_PROFILE = "Posts, likes, replies done during the last year";
private final static String TOOLTIP_ACTIVITY_VRE = "Posts, likes, replies done in the last year in this VRE";
private final static String TOOLTIP_GOT_ROOT_PROFILE = "Likes and post replies got during the last year";
@@ -310,8 +313,9 @@ public class StatisticsPanel extends Composite {
// append widget
mainPanel.add(activityGotWidgetContainer);
- // the storage and the profile strength(only in root)
+ // the storage, quota, and the profile strength(only in root)
final StatisticWidget storage = new StatisticWidget(isRoot);
+ final StatisticWidget quotaStorage = new StatisticWidget(isRoot);
final StatisticWidget profileStrength = new StatisticWidget(isRoot);
if(isRoot || isProfilePage){
@@ -326,6 +330,16 @@ public class StatisticsPanel extends Composite {
mainPanel.add(storage);
+ quotaStorage.setHeader(QUOTA_LABEL);
+ quotaStorage.setToolTip(TOOLTIP_QUOTA_SPACE);
+
+ // add loading image that will be replaced by the incoming values
+ Image quotaLoader = new Image(imagePath);
+ quotaLoader.setStyleName("loading-image-center-small");
+ quotaStorage.appendToPanel(quotaLoader);
+
+ mainPanel.add(quotaStorage);
+
profileStrength.setHeader(PROFILE_STRENGTH_LABEL);
profileStrength.setToolTip(TOOLTIP_PROFILE_STRENGHT);
@@ -363,6 +377,35 @@ public class StatisticsPanel extends Composite {
}
});
+ // require quota information
+ statisticsService.getQuotaStorage(userid, new AsyncCallback() {
+
+ @Override
+ public void onSuccess(QuotaInfo quota) {
+
+ if(quota == null){
+ quotaStorage.setVisible(false);
+ }else{
+ long max = quota.getMax();
+ long current = quota.getCurrent();
+ long percent = Long.divideUnsigned(current, max);
+ quotaStorage.clearPanelValues();
+ Button quotaStorageValue = new Button();
+ quotaStorageValue.setType(ButtonType.LINK);
+ quotaStorageValue.setText(percent + "%");
+ quotaStorageValue.addStyleName("buttons-statistics-disabled-events");
+ quotaStorage.appendToPanel(quotaStorageValue);
+ }
+
+ }
+
+ @Override
+ public void onFailure(Throwable arg0) {
+ quotaStorage.setVisible(false);
+ }
+ });
+
+ // require profile strenght
statisticsService.getProfileStrength(userid, new AsyncCallback() {
@Override
diff --git a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/UserStatisticsService.java b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/UserStatisticsService.java
index d139f1d..a01300b 100644
--- a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/UserStatisticsService.java
+++ b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/UserStatisticsService.java
@@ -1,6 +1,7 @@
package org.gcube.portlet.user.userstatisticsportlet.client;
import org.gcube.portlet.user.userstatisticsportlet.shared.PostsStatsBean;
+import org.gcube.portlet.user.userstatisticsportlet.shared.QuotaInfo;
import org.gcube.portlet.user.userstatisticsportlet.shared.UserInformation;
import com.google.gwt.user.client.rpc.RemoteService;
@@ -30,6 +31,11 @@ public interface UserStatisticsService extends RemoteService {
*/
String getTotalSpaceInUse(String userid);
+ /**
+ * get quota (about storage) information
+ */
+ QuotaInfo getQuotaStorage(String userid);
+
/**
* get profile strenght
*/
diff --git a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/UserStatisticsServiceAsync.java b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/UserStatisticsServiceAsync.java
index c670c19..dcb410f 100644
--- a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/UserStatisticsServiceAsync.java
+++ b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/client/UserStatisticsServiceAsync.java
@@ -1,6 +1,7 @@
package org.gcube.portlet.user.userstatisticsportlet.client;
import org.gcube.portlet.user.userstatisticsportlet.shared.PostsStatsBean;
+import org.gcube.portlet.user.userstatisticsportlet.shared.QuotaInfo;
import org.gcube.portlet.user.userstatisticsportlet.shared.UserInformation;
import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -21,4 +22,6 @@ public interface UserStatisticsServiceAsync {
void setShowMyOwnStatisticsToOtherPeople(boolean show,
AsyncCallback callback);
+
+ void getQuotaStorage(String userid, AsyncCallback callback);
}
diff --git a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/UserStatisticsServiceImpl.java b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/UserStatisticsServiceImpl.java
index 2154279..efa87e5 100644
--- a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/UserStatisticsServiceImpl.java
+++ b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/UserStatisticsServiceImpl.java
@@ -1,5 +1,7 @@
package org.gcube.portlet.user.userstatisticsportlet.server;
+import java.io.InputStream;
+import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
@@ -7,17 +9,24 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathFactory;
+
import org.gcube.common.homelibrary.home.HomeLibrary;
import org.gcube.common.homelibrary.home.workspace.Workspace;
import org.gcube.common.portal.PortalContext;
-import org.gcube.portal.custom.communitymanager.SiteManagerUtil;
import org.gcube.portal.databook.server.DBCassandraAstyanaxImpl;
import org.gcube.portal.databook.server.DatabookStore;
import org.gcube.portal.databook.shared.Comment;
import org.gcube.portal.databook.shared.Feed;
import org.gcube.portlet.user.userstatisticsportlet.client.UserStatisticsService;
+import org.gcube.portlet.user.userstatisticsportlet.server.cache.UserInfrastructureQuotaStorageCache;
import org.gcube.portlet.user.userstatisticsportlet.server.cache.UserInfrastructureSpaceCache;
+import org.gcube.portlet.user.userstatisticsportlet.server.utils.DiscoverQuotaServiceEndPoint;
import org.gcube.portlet.user.userstatisticsportlet.shared.PostsStatsBean;
+import org.gcube.portlet.user.userstatisticsportlet.shared.QuotaInfo;
import org.gcube.portlet.user.userstatisticsportlet.shared.UserInformation;
import org.gcube.vomanagement.usermanagement.GroupManager;
import org.gcube.vomanagement.usermanagement.UserManager;
@@ -25,6 +34,7 @@ import org.gcube.vomanagement.usermanagement.impl.LiferayGroupManager;
import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager;
import org.gcube.vomanagement.usermanagement.model.GCubeGroup;
import org.gcube.vomanagement.usermanagement.util.ManagementUtils;
+import org.w3c.dom.Document;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.liferay.portal.kernel.cache.CacheRegistryUtil;
@@ -42,6 +52,7 @@ public class UserStatisticsServiceImpl extends RemoteServiceServlet implements U
// private static final org.slf4j.Logger logger = LoggerFactory.getLogger(UserStatisticsServiceImpl.class);
private static final Log logger = LogFactoryUtil.getLog(UserStatisticsServiceImpl.class);
private DatabookStore store;
+ private String quotaServiceBaseUrl;
private static final String CUSTOM_FIELD_NAME_USER_STATISTICS_VISIBILITY = "show_user_statistics_other_people";
private UserManager userManager = new LiferayUserManager();
private GroupManager groupManager = new LiferayGroupManager();
@@ -51,6 +62,9 @@ public class UserStatisticsServiceImpl extends RemoteServiceServlet implements U
logger.info("Getting connection to Cassandra..");
store = new DBCassandraAstyanaxImpl();
ServerUtils.createUserCustomField(CUSTOM_FIELD_NAME_USER_STATISTICS_VISIBILITY, true);
+
+ logger.info("Retrieving quota service endpoint");
+ quotaServiceBaseUrl = DiscoverQuotaServiceEndPoint.discover();
}
@Override
@@ -59,6 +73,62 @@ public class UserStatisticsServiceImpl extends RemoteServiceServlet implements U
store.closeConnection();
}
+ @Override
+ public QuotaInfo getQuotaStorage(String userid) {
+
+ QuotaInfo toReturn = null;
+ String userName = null;
+
+ if(quotaServiceBaseUrl != null){
+
+ userName = ServerUtils.getCurrentUser(this.getThreadLocalRequest()).getUsername();
+ String quotaOfUser = userName;
+
+ // do not show quota info to other users
+ if(userid != null && !userid.equals(userName))
+ return null;
+
+ logger.debug("Fetching info for quota of user " + quotaOfUser);
+
+ try{
+
+ UserInfrastructureQuotaStorageCache cache = UserInfrastructureQuotaStorageCache.getCacheInstance();
+
+ if(cache.get(userName) != null)
+ toReturn = cache.get(userName);
+ else{
+
+ // ask the service ...
+ PortalContext pContext = PortalContext.getConfiguration();
+ String rootContextToken = pContext.getCurrentUserToken("/" + pContext.getInfrastructureName(), userName);
+ URL request = new URL(quotaServiceBaseUrl + "?timeinterval=FOREVER&gcube-token=" + rootContextToken);
+ InputStream result = request.openStream();
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+ Document document = dBuilder.parse(result);
+ document.getDocumentElement().normalize();
+
+ logger.debug("Result is " + document);
+ // look for the properties
+
+ // TO BE PARSED TODO
+ XPathFactory xpf = XPathFactory.newInstance();
+ XPath xp = xpf.newXPath();
+ //String text = xp.evaluate("//add[@job='351']/tag[position()=1]/text()",
+ // document.getDocumentElement());
+
+ // PUSH INTO THE CACHE
+ }
+ }catch(Exception e){
+ logger.error("Failed to retrieve quota information for user", e);
+ }
+
+ }
+
+ logger.debug("Quota for user " + userName + " is " + toReturn);
+ return toReturn;
+ }
+
@Override
public String getTotalSpaceInUse(String userid) {
String storageInUse = null;
diff --git a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/cache/UserInfrastructureQuotaStorageCache.java b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/cache/UserInfrastructureQuotaStorageCache.java
new file mode 100644
index 0000000..940cc85
--- /dev/null
+++ b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/cache/UserInfrastructureQuotaStorageCache.java
@@ -0,0 +1,73 @@
+package org.gcube.portlet.user.userstatisticsportlet.server.cache;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.gcube.portlet.user.userstatisticsportlet.shared.QuotaInfo;
+
+import com.liferay.portal.kernel.log.Log;
+import com.liferay.portal.kernel.log.LogFactoryUtil;
+
+
+/**
+ * Cache for the user's storage quota max/in-use within the infrastructure
+ * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
+ */
+public class UserInfrastructureQuotaStorageCache implements CacheInterface {
+
+ //private static final org.slf4j.Logger logger = LoggerFactory.getLogger(UserInfrastructureSpaceCache.class);
+ private static final Log logger = LogFactoryUtil.getLog(UserInfrastructureSpaceCache.class);
+
+ /**
+ * The instance
+ */
+ private static UserInfrastructureQuotaStorageCache instance = new UserInfrastructureQuotaStorageCache();
+
+ /**
+ * The hashmap
+ */
+ private Map> userQuotaMap;
+
+ /**
+ * Cache entry expires after EXPIRED_AFTER ms
+ */
+ private static final long EXPIRED_AFTER = 1000 * 60 * 60; // an hour
+
+ /**
+ * Private constructor
+ */
+ private UserInfrastructureQuotaStorageCache(){
+ userQuotaMap = new ConcurrentHashMap<>();
+ }
+
+ /**
+ * Retrieve the current cache instance object
+ * @return
+ */
+ public static UserInfrastructureQuotaStorageCache getCacheInstance(){
+ return instance;
+ }
+
+ @Override
+ public QuotaInfo get(String key) {
+
+ if(userQuotaMap.containsKey(key)){
+ CacheValueBean bean = userQuotaMap.get(key);
+ if(CacheUtilities.expired(bean.getTTL(), EXPIRED_AFTER)){
+ userQuotaMap.remove(key);
+ logger.debug("Amount of space in the infrastructure used expired for key " + key + ", returning null");
+ }
+ else
+ return bean.getValue();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean insert(String key, QuotaInfo value) {
+ CacheValueBean newBean = new CacheValueBean(value, System.currentTimeMillis());
+ userQuotaMap.put(key, newBean);
+ return true;
+ }
+
+}
diff --git a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/cache/UserInfrastructureSpaceCache.java b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/cache/UserInfrastructureSpaceCache.java
index 72871ec..dbb4131 100644
--- a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/cache/UserInfrastructureSpaceCache.java
+++ b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/cache/UserInfrastructureSpaceCache.java
@@ -8,8 +8,7 @@ import com.liferay.portal.kernel.log.LogFactoryUtil;
/**
* Cache for the user's space in use within the infrastructure
- * @author Costantino Perciante at ISTI-CNR
- * (costantino.perciante@isti.cnr.it)
+ * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class UserInfrastructureSpaceCache implements CacheInterface {
diff --git a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/utils/DiscoverQuotaServiceEndPoint.java b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/utils/DiscoverQuotaServiceEndPoint.java
new file mode 100644
index 0000000..b5e7c97
--- /dev/null
+++ b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/server/utils/DiscoverQuotaServiceEndPoint.java
@@ -0,0 +1,91 @@
+package org.gcube.portlet.user.userstatisticsportlet.server.utils;
+
+import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
+import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.gcube.common.portal.PortalContext;
+import org.gcube.common.resources.gcore.ServiceEndpoint;
+import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint;
+import org.gcube.common.resources.gcore.ServiceEndpoint.Property;
+import org.gcube.common.scope.api.ScopeProvider;
+import org.gcube.resources.discovery.client.api.DiscoveryClient;
+import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
+
+import com.liferay.portal.kernel.log.Log;
+import com.liferay.portal.kernel.log.LogFactoryUtil;
+
+
+/**
+ * Discover the base path of the QuotaServiceEndPoint
+ * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
+ */
+public class DiscoverQuotaServiceEndPoint {
+
+ private static final Log logger = LogFactoryUtil.getLog(DiscoverQuotaServiceEndPoint.class);
+
+ // info to retrieve it
+ private static final String SERVICE_TYPE = "Quota";
+ private static final String SERVICE_NAME = "Persistence";
+ private static final String SERVICE_PROPERTY = "urlService";
+
+ public static String discover(){
+
+ // this service endpoint needs to be discovered into the root
+ String basePath = null;
+ String currentContext = ScopeProvider.instance.get();
+ try{
+
+ PortalContext pc = PortalContext.getConfiguration();
+ String rootScope = "/" + pc.getInfrastructureName();
+ ScopeProvider.instance.set(rootScope);
+
+ // perform the query
+ logger.info("Looking up " + SERVICE_TYPE + " service in context " + rootScope);
+ List resources = getConfigurationFromIS();
+
+ if(resources == null || resources.isEmpty())
+ throw new RuntimeException("Missing service endpoint for " + SERVICE_TYPE);
+ else{
+
+ Iterator accessPointIterator = resources.get(0).profile().accessPoints().iterator();
+ while (accessPointIterator.hasNext()) {
+ ServiceEndpoint.AccessPoint accessPoint = (ServiceEndpoint.AccessPoint) accessPointIterator
+ .next();
+
+ Map propertiesMap = accessPoint.propertyMap();
+ basePath = (String)propertiesMap.get(SERVICE_PROPERTY).value();
+
+ }
+
+ }
+ basePath = basePath == null ? basePath : basePath + "gcube/service/quotaStatus/detail";
+ logger.info("Base path value is " + basePath);
+ }catch(Exception e){
+ logger.error("The following errore arose while looking up service endpoint for " + SERVICE_TYPE, e);
+ }finally{
+ ScopeProvider.instance.set(currentContext);
+ }
+
+ return basePath;
+ }
+
+ /**
+ * Retrieve endpoints information from IS
+ * @return the service endpoint
+ * @throws Exception
+ */
+ private static List getConfigurationFromIS() throws Exception{
+
+ SimpleQuery query = queryFor(ServiceEndpoint.class);
+ query.addCondition("$resource/Profile/Name/text() eq '"+ SERVICE_NAME +"'");
+ query.addCondition("$resource/Profile/Category/text() eq '"+ SERVICE_TYPE +"'");
+ DiscoveryClient client = clientFor(ServiceEndpoint.class);
+ List toReturn = client.submit(query);
+ return toReturn;
+
+ }
+}
diff --git a/src/main/java/org/gcube/portlet/user/userstatisticsportlet/shared/QuotaInfo.java b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/shared/QuotaInfo.java
new file mode 100644
index 0000000..ecee81a
--- /dev/null
+++ b/src/main/java/org/gcube/portlet/user/userstatisticsportlet/shared/QuotaInfo.java
@@ -0,0 +1,40 @@
+package org.gcube.portlet.user.userstatisticsportlet.shared;
+
+import java.io.Serializable;
+
+/**
+ * A quota info bean: maximum and current value are contained in it.
+ * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
+ */
+public class QuotaInfo implements Serializable{
+
+ private static final long serialVersionUID = 1L;
+ private long max;
+ private long current;
+
+ public QuotaInfo() {
+ super();
+ }
+
+ public QuotaInfo(long max, long current) {
+ super();
+ this.max = max;
+ this.current = current;
+ }
+ public long getMax() {
+ return max;
+ }
+ public void setMax(long max) {
+ this.max = max;
+ }
+ public long getCurrent() {
+ return current;
+ }
+ public void setCurrent(long current) {
+ this.current = current;
+ }
+ @Override
+ public String toString() {
+ return "QuotaInfo [max=" + max + ", current=" + current + "]";
+ }
+}