hashtags = result.getHashtags();
+ if (hashtags == null) {
+ showServError();
+ }
+ else {
+ if (!result.isInfrastructure() && hashtags != null && !hashtags.isEmpty()) {
+ mainPanel.setStyleName("trending-frame");
+ HTML name = new HTML(DISPLAY_NAME);
+ name.setStyleName("topic-title");
+ mainPanel.add(name);
+ }
+ if (hashtags != null) {
+ for (String hashtag : hashtags) {
+ HTML toAdd = new HTML(hashtag);
+ toAdd.addStyleName("hashtag-label");
+ mainPanel.add(toAdd);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ showConnError();
+ }
+ });
+ }
+
+ private void showLoader() {
+ mainPanel.clear();
+ mainPanel.setWidth("100%");
+ mainPanel.setHorizontalAlignment(HasAlignment.ALIGN_CENTER);
+ mainPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
+ mainPanel.add(loadingImage);
+ }
+
+ private void showConnError() {
+ mainPanel.clear();
+ mainPanel.setHorizontalAlignment(HasAlignment.ALIGN_LEFT);
+ mainPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP);
+ mainPanel.add(new HTML("" +
+ "Sorry, looks like something is broken with the server connection
" +
+ "Please check your connection and try refresh this page.
"));
+ }
+
+ private void showServError() {
+ mainPanel.clear();
+ mainPanel.add(new HTML("" +
+ "Sorry, we have problems in our servers ...
" +
+ "Please try in a while or report the issue.
"));
+ }
+}
diff --git a/src/main/java/org/gcube/portlets/user/topics/server/TopicServiceImpl.java b/src/main/java/org/gcube/portlets/user/topics/server/TopicServiceImpl.java
new file mode 100644
index 0000000..e8267a7
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/user/topics/server/TopicServiceImpl.java
@@ -0,0 +1,175 @@
+package org.gcube.portlets.user.topics.server;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.commons.codec.binary.Base64;
+import org.gcube.application.framework.core.session.ASLSession;
+import org.gcube.application.framework.core.session.SessionManager;
+import org.gcube.common.scope.impl.ScopeBean;
+import org.gcube.common.scope.impl.ScopeBean.Type;
+import org.gcube.portal.custom.communitymanager.OrganizationsUtil;
+import org.gcube.portal.custom.scopemanager.scopehelper.ScopeHelper;
+import org.gcube.portal.databook.client.GCubeSocialNetworking;
+import org.gcube.portal.databook.server.DBCassandraAstyanaxImpl;
+import org.gcube.portal.databook.server.DatabookStore;
+import org.gcube.portlets.user.topics.client.TopicService;
+import org.gcube.portlets.user.topics.shared.HashTagAndOccurrence;
+import org.gcube.portlets.user.topics.shared.HashtagsWrapper;
+import org.gcube.vomanagement.usermanagement.GroupManager;
+import org.gcube.vomanagement.usermanagement.impl.liferay.LiferayGroupManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gwt.user.server.rpc.RemoteServiceServlet;
+import com.liferay.portal.model.Organization;
+import com.liferay.portal.model.User;
+import com.liferay.portal.service.UserLocalServiceUtil;
+
+/**
+ * @author Massimiliano Assante, ISTI-CNR
+ */
+@SuppressWarnings("serial")
+public class TopicServiceImpl extends RemoteServiceServlet implements TopicService {
+ private static final Logger _log = LoggerFactory.getLogger(TopicServiceImpl.class);
+
+ public static final String TEST_USER = "test.user";
+ /**
+ * The Cassandra store interface
+ */
+ private DatabookStore store;
+ /**
+ * connect to cassandra at startup
+ */
+ public void init() {
+ store = new DBCassandraAstyanaxImpl();
+ }
+
+ public void destroy() {
+ store.closeConnection();
+ }
+ /**
+ * the current ASLSession
+ * @return the session
+ */
+ private ASLSession getASLSession() {
+ String sessionID = this.getThreadLocalRequest().getSession().getId();
+ String user = (String) this.getThreadLocalRequest().getSession().getAttribute(ScopeHelper.USERNAME_ATTRIBUTE);
+ if (user == null) {
+ _log.warn("USER IS NULL setting test.user and Running OUTSIDE PORTAL");
+ user = getDevelopmentUser();
+ SessionManager.getInstance().getASLSession(sessionID, user).setScope("/gcube/devsec/devVRE");
+ }
+ return SessionManager.getInstance().getASLSession(sessionID, user);
+ }
+ /**
+ * when packaging test will fail if the user is not set to test.user
+ * @return .
+ */
+ public String getDevelopmentUser() {
+ String user = TEST_USER;
+ //user = "massimiliano.assante";
+ return user;
+ }
+ /**
+ *
+ * @return true if you're running into the portal, false if in development
+ */
+ private boolean isWithinPortal() {
+ try {
+ UserLocalServiceUtil.getService();
+ return true;
+ }
+ catch (com.liferay.portal.kernel.bean.BeanLocatorException ex) {
+ _log.trace("Development Mode ON");
+ return false;
+ }
+ }
+ /**
+ * return the top 10 hashtag with max occurrence
+ */
+ @Override
+ public HashtagsWrapper getHashtags() {
+ ArrayList hashtagsChart = new ArrayList<>();
+ ASLSession session = getASLSession();
+
+ String userName = session.getUsername();
+ boolean isInfrastructure = isInfrastructureScope();
+ try {
+ //in case the portal is restarted and you have the social home open it will get test.user (no callback to set session info)
+ //this check just return nothing if that happens
+ if (userName.compareTo("test.user") == 0) {
+ _log.debug("Found " + userName + " returning nothing");
+ return null;
+ }
+ ArrayList toSort = new ArrayList();
+ /**
+ * this handles the case where the portlet is deployed outside of VREs (regular)
+ */
+
+ if (isInfrastructure) {
+ _log.debug("****** retrieving hashtags for user VREs");
+ User currUser = OrganizationsUtil.validateUser(userName);
+ GroupManager gm = new LiferayGroupManager();
+ for (Organization org : currUser.getOrganizations()) {
+ if (gm.isVRE(org.getOrganizationId()+"")) {
+ String vreid = gm.getScope(""+org.getOrganizationId()); //get the scope
+ Map map = store.getVREHashtagsWithOccurrence(vreid);
+ for (String hashtag : map.keySet()) {
+ toSort.add(new HashTagAndOccurrence(hashtag, map.get(hashtag)));
+ }
+ }
+ }
+ }
+ //else must be in a VRE scope
+ else {
+ String scope = session.getScope();
+ _log.debug("****** retrieving hashtags for scope " + scope);
+ Map map = store.getVREHashtagsWithOccurrence(scope);
+ for (String hashtag : map.keySet()) {
+ toSort.add(new HashTagAndOccurrence(hashtag, map.get(hashtag)));
+ }
+ }
+
+ Collections.sort(toSort, Collections.reverseOrder());
+ int i = 0;
+ for (HashTagAndOccurrence wrapper : toSort) {
+ String hashtag = wrapper.getHashtag();
+
+ String href="\"?"+
+ new String(Base64.encodeBase64(GCubeSocialNetworking.HASHTAG_OID.getBytes()))+"="+
+ new String(Base64.encodeBase64(hashtag.getBytes()))+"\"";
+ String hashtagLink = ""+hashtag+"";
+ hashtagsChart.add(hashtagLink);
+ i++;
+ if (i >= 10)
+ break;
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ return new HashtagsWrapper(isInfrastructure, hashtagsChart);
+ }
+
+
+ /**
+ * Indicates whether the scope is the whole infrastructure.
+ * @return true
if it is, false
otherwise.
+ */
+ private boolean isInfrastructureScope() {
+ boolean toReturn = false;
+ try {
+ ScopeBean scope = new ScopeBean(getASLSession().getScope());
+ toReturn = scope.is(Type.INFRASTRUCTURE);
+ return toReturn;
+ }
+ catch (NullPointerException e) {
+ _log.error("NullPointerException in isInfrastructureScope returning false");
+ return false;
+ }
+ }
+
+}
diff --git a/src/main/java/org/gcube/portlets/user/topics/server/portlet/TopicsPortlet.java b/src/main/java/org/gcube/portlets/user/topics/server/portlet/TopicsPortlet.java
new file mode 100644
index 0000000..c648107
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/user/topics/server/portlet/TopicsPortlet.java
@@ -0,0 +1,26 @@
+package org.gcube.portlets.user.topics.server.portlet;
+
+import java.io.IOException;
+
+import javax.portlet.ActionRequest;
+import javax.portlet.ActionResponse;
+import javax.portlet.GenericPortlet;
+import javax.portlet.PortletException;
+import javax.portlet.PortletRequestDispatcher;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+
+import org.gcube.portal.custom.scopemanager.scopehelper.ScopeHelper;
+
+public class TopicsPortlet extends GenericPortlet {
+ public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
+ response.setContentType("text/html");
+ ScopeHelper.setContext(request);
+ PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher("/WEB-INF/jsp/Topics_view.jsp");
+ dispatcher.include(request, response);
+ }
+
+ public void processAction(ActionRequest request, ActionResponse response)
+ throws PortletException, IOException {
+ }
+}
diff --git a/src/main/java/org/gcube/portlets/user/topics/shared/HashTagAndOccurrence.java b/src/main/java/org/gcube/portlets/user/topics/shared/HashTagAndOccurrence.java
new file mode 100644
index 0000000..5315f7a
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/user/topics/shared/HashTagAndOccurrence.java
@@ -0,0 +1,35 @@
+package org.gcube.portlets.user.topics.shared;
+
+public class HashTagAndOccurrence implements Comparable{
+ private String hashtag;
+ private Integer occurrence;
+ public HashTagAndOccurrence(String hashtag, Integer occurrence) {
+ super();
+ this.hashtag = hashtag;
+ this.occurrence = occurrence;
+ }
+ public String getHashtag() {
+ return hashtag;
+ }
+ public void setHashtag(String hashtag) {
+ this.hashtag = hashtag;
+ }
+ public Integer getOccurrence() {
+ return occurrence;
+ }
+ public void setOccurrence(Integer occurrence) {
+ this.occurrence = occurrence;
+ }
+ @Override
+ public String toString() {
+ return "HashTagAndOccurrence [hashtag=" + hashtag + ", occurrence="
+ + occurrence + "]";
+ }
+ @Override
+ public int compareTo(HashTagAndOccurrence o) {
+ if (this.occurrence == o.getOccurrence()) return 0;
+ return (this.occurrence > o.getOccurrence()) ? 1 : -1;
+ }
+
+
+}
diff --git a/src/main/java/org/gcube/portlets/user/topics/shared/HashtagsWrapper.java b/src/main/java/org/gcube/portlets/user/topics/shared/HashtagsWrapper.java
new file mode 100644
index 0000000..63ed75f
--- /dev/null
+++ b/src/main/java/org/gcube/portlets/user/topics/shared/HashtagsWrapper.java
@@ -0,0 +1,31 @@
+package org.gcube.portlets.user.topics.shared;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+public class HashtagsWrapper implements Serializable {
+ private boolean isInfrastructure;
+ private ArrayList hashtags;
+ public HashtagsWrapper(boolean isInfrastructure, ArrayList hashtags) {
+ super();
+ this.isInfrastructure = isInfrastructure;
+ this.hashtags = hashtags;
+ }
+ public boolean isInfrastructure() {
+ return isInfrastructure;
+ }
+ public void setInfrastructure(boolean isInfrastructure) {
+ this.isInfrastructure = isInfrastructure;
+ }
+ public ArrayList getHashtags() {
+ return hashtags;
+ }
+ public void setHashtags(ArrayList hashtags) {
+ this.hashtags = hashtags;
+ }
+ public HashtagsWrapper() {
+ super();
+ // TODO Auto-generated constructor stub
+ }
+
+}
diff --git a/src/main/resources/clientlog4j.properties b/src/main/resources/clientlog4j.properties
new file mode 100644
index 0000000..4a2e1cd
--- /dev/null
+++ b/src/main/resources/clientlog4j.properties
@@ -0,0 +1,12 @@
+log4j.rootLogger=DEBUG, A1
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+
+# Print the date in ISO 8601 format
+log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
+
+# Print only messages of level TRACE or above in the package org.gcube
+log4j.logger.org.gcube=TRACE
+log4j.logger.org.gcube.application.framework.core.session=INFO
+log4j.logger.org.gcube.common.scope.impl.DefaultScopeProvider=ERROR
+log4j.logger.com.netflix.astyanax.connectionpool.impl.CountingConnectionPoolMonitor=ERROR
\ No newline at end of file
diff --git a/src/main/resources/org/gcube/portlets/user/topics/TopTopics.gwt.xml b/src/main/resources/org/gcube/portlets/user/topics/TopTopics.gwt.xml
new file mode 100644
index 0000000..477a15c
--- /dev/null
+++ b/src/main/resources/org/gcube/portlets/user/topics/TopTopics.gwt.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/webapp/TopTopics.css b/src/main/webapp/TopTopics.css
new file mode 100644
index 0000000..9cf9223
--- /dev/null
+++ b/src/main/webapp/TopTopics.css
@@ -0,0 +1,41 @@
+#Trending-Topics-Container {
+ margin-right: 20px;
+}
+
+.topic-title {
+ display: block;
+ font-size: 16px;
+ color: #555;
+ font-weight: 400;
+ margin-bottom: 10px;
+}
+
+.trending-frame {
+ margin: 0 0 10px;
+ padding: 10px;
+ margin: 0px 5px;
+ background-color: #FFF;
+ border-radius: 6px !important;
+ -moz-border-radius: 6px !important;
+ -webkit-border-radius: 6px !important;
+ border: 1px solid #DBDBDB;
+}
+
+a.topiclink,a.topiclink:active,a.topiclink:visited {
+ font-family: 'Lucida Grande', Verdana, 'Bitstream Vera Sans', Arial,
+ sans-serif;
+ font-size: 15px;
+ cursor: pointer;
+ cursor: hand;
+ text-decoration: none;
+ color: #3B5998;
+}
+
+a.topiclink:hover {
+ opacity: 0.8;
+ text-decoration: underline;
+}
+
+.hashtag-label {
+ padding: 0 5px 1px;
+}
\ No newline at end of file
diff --git a/src/main/webapp/TopTopics.html b/src/main/webapp/TopTopics.html
new file mode 100644
index 0000000..f4b2ed1
--- /dev/null
+++ b/src/main/webapp/TopTopics.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Trending Topics Project
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/webapp/WEB-INF/jsp/Topics_view.jsp b/src/main/webapp/WEB-INF/jsp/Topics_view.jsp
new file mode 100644
index 0000000..c8fd050
--- /dev/null
+++ b/src/main/webapp/WEB-INF/jsp/Topics_view.jsp
@@ -0,0 +1,6 @@
+<%@page contentType="text/html"%>
+<%@page pageEncoding="UTF-8"%>
+
+
+
+
diff --git a/src/main/webapp/WEB-INF/liferay-display.xml b/src/main/webapp/WEB-INF/liferay-display.xml
new file mode 100644
index 0000000..869751a
--- /dev/null
+++ b/src/main/webapp/WEB-INF/liferay-display.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/liferay-plugin-package.properties b/src/main/webapp/WEB-INF/liferay-plugin-package.properties
new file mode 100644
index 0000000..b5e54b2
--- /dev/null
+++ b/src/main/webapp/WEB-INF/liferay-plugin-package.properties
@@ -0,0 +1,9 @@
+name=Topics
+module-group-id=liferay
+module-incremental-version=1
+tags=
+short-description=
+change-log=
+page-url=http://www.d4science.org
+author=D4Science.org
+licenses=EUPL
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/liferay-portlet.xml b/src/main/webapp/WEB-INF/liferay-portlet.xml
new file mode 100644
index 0000000..c2546fd
--- /dev/null
+++ b/src/main/webapp/WEB-INF/liferay-portlet.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+ Topics
+ false
+ false
+ false
+ /TrendingTopics.css
+
+
+ administrator
+ Administrator
+
+
+ guest
+ Guest
+
+
+ power-user
+ Power User
+
+
+ user
+ User
+
+
diff --git a/src/main/webapp/WEB-INF/portlet.xml b/src/main/webapp/WEB-INF/portlet.xml
new file mode 100644
index 0000000..918ae16
--- /dev/null
+++ b/src/main/webapp/WEB-INF/portlet.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ Topics
+ Top Topics
+ org.gcube.portlets.user.topics.server.portlet.TopicsPortlet
+
+ view-jsp
+ /view.jsp
+
+ 0
+
+ text/html
+
+
+ Top Topics
+ Top Topics
+ Top Topics
+
+
+ administrator
+
+
+
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..84454ed
--- /dev/null
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+ topicsServlet
+ org.gcube.portlets.user.topics.server.TopicServiceImpl
+
+
+
+ topicsServlet
+ /toptopics/topicservice
+
+
+
+
+ TrendingTopics.html
+
+
+
diff --git a/src/main/webapp/images/topics-loader.gif b/src/main/webapp/images/topics-loader.gif
new file mode 100644
index 0000000..89ae681
Binary files /dev/null and b/src/main/webapp/images/topics-loader.gif differ
diff --git a/src/test/java/org/gcube/portlets/user/topics/test/TestForDeploy.java b/src/test/java/org/gcube/portlets/user/topics/test/TestForDeploy.java
new file mode 100644
index 0000000..9749c88
--- /dev/null
+++ b/src/test/java/org/gcube/portlets/user/topics/test/TestForDeploy.java
@@ -0,0 +1,19 @@
+package org.gcube.portlets.user.topics.test;
+
+import static org.junit.Assert.*;
+
+import org.gcube.portlets.user.topics.server.TopicServiceImpl;
+import org.junit.Test;
+
+public class TestForDeploy {
+
+ @Test
+ public void testUserIsTestUser() {
+ TopicServiceImpl serviceImpl = new TopicServiceImpl();
+ String username = serviceImpl.getDevelopmentUser();
+ System.out.println("username for deploy is: " + username);
+ assertTrue(username.compareTo(TopicServiceImpl.TEST_USER) == 0);
+ System.out.println("Test OK!");
+ }
+
+}