- Added portlet for PerformFISH KPI-Data generation

This commit is contained in:
Massimiliano Assante 2021-01-22 19:53:13 +01:00
parent c8c054c491
commit e43a04cb8e
15 changed files with 532 additions and 5 deletions

View File

@ -8,7 +8,9 @@ org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8 org.eclipse.jdt.core.compiler.source=1.8

View File

@ -1,13 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0"> <?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="thematic-gateways-portlet"> <wb-module deploy-name="thematic-gateways-portlet">
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/> <wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/> <wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/> <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/> <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<dependent-module archiveName="detachedres-library-1.1.0.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/detachedres-library/detachedres-library">
<dependency-type>uses</dependency-type>
</dependent-module>
<property name="context-root" value="thematic-gateways-portlet"/> <property name="context-root" value="thematic-gateways-portlet"/>
<property name="java-output-path" value="/thematic-gateways-portlet/target/classes"/> <property name="java-output-path" value="/thematic-gateways-portlet/target/classes"/>
</wb-module> </wb-module>
</project-modules> </project-modules>

View File

@ -0,0 +1,7 @@
<root>
<facet id="jst.jaxrs">
<node name="libprov">
<attribute name="provider-id" value="jaxrs-no-op-library-provider"/>
</node>
</facet>
</root>

View File

@ -5,4 +5,5 @@
<installed facet="jst.web" version="2.4"/> <installed facet="jst.web" version="2.4"/>
<installed facet="liferay.portlet" version="6.0"/> <installed facet="liferay.portlet" version="6.0"/>
<installed facet="wst.jsdt.web" version="1.0"/> <installed facet="wst.jsdt.web" version="1.0"/>
<installed facet="jst.jaxrs" version="2.0"/>
</faceted-project> </faceted-project>

View File

@ -1,5 +1,8 @@
# Changelog # Changelog
## [v7.2.0-SNAPSHOT] - 2021-01-22
- Added portlet for PerformFISH KPI-Data generation
## [v7.1.0] - 2020-10-09 ## [v7.1.0] - 2020-10-09

28
pom.xml
View File

@ -14,7 +14,7 @@
<artifactId>thematic-gateways-portlet</artifactId> <artifactId>thematic-gateways-portlet</artifactId>
<packaging>war</packaging> <packaging>war</packaging>
<name>thematic-gateways-portlet Portlets</name> <name>thematic-gateways-portlet Portlets</name>
<version>7.1.0</version> <version>7.2.0-SNAPSHOT</version>
<description> <description>
Thematic Gateways Portlet Thematic Gateways Portlet
</description> </description>
@ -66,10 +66,34 @@
<artifactId>commons-beanutils</artifactId> <artifactId>commons-beanutils</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>storagehub-client-library</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>storagehub-model</artifactId>
</dependency>
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>portal-service</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>authorization-client</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>common-authorization</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.liferay.portal</groupId> <groupId>com.liferay.portal</groupId>
<artifactId>portal-service</artifactId> <artifactId>portal-service</artifactId>
<version>${liferay.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -0,0 +1,35 @@
package org.gube.portlets.user.kpidata;
public class CallResult {
boolean success;
String comment;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public CallResult(boolean success, String comment) {
super();
this.success = success;
this.comment = comment;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("CallResult [success=");
builder.append(success);
builder.append(", comment=");
builder.append(comment);
builder.append("]");
return builder.toString();
}
}

View File

@ -0,0 +1,78 @@
package org.gube.portlets.user.kpidata;
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.resources.gcore.GCoreEndpoint;
import org.gcube.common.resources.gcore.GCoreEndpoint.Profile.Endpoint;
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;
public class KPIdataUtils {
private static Log _log = LogFactoryUtil.getLog(KPIdataUtils.class);
private static String ANALYTICAL_TOOLKIT_SERVICE_GCORE_ENDPOINT_NAME = "perform-service";
private static String ANALYTICAL_TOOLKIT_SERVICE_GCORE_ENDPOINT_CLASS = "Application";
public static String ANALYTICAL_TOOLKIT_SERVICE_INTERFACE_NAME = "org.gcube.application.perform.service.PerformService";
public KPIdataUtils() {
// TODO Auto-generated constructor stub
}
public static String getCurrentContext(long groupId) {
try {
PortalContext pContext = PortalContext.getConfiguration();
return pContext.getCurrentScope(""+groupId);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static List<GCoreEndpoint> getAnalyticalToolkitServiceInstance(String context) throws Exception {
String currScope = ScopeProvider.instance.get();
ScopeProvider.instance.set(context);
SimpleQuery query = queryFor(GCoreEndpoint.class);
query.addCondition("$resource/Profile/ServiceClass/text() eq '"+ ANALYTICAL_TOOLKIT_SERVICE_GCORE_ENDPOINT_CLASS +"'");
query.addCondition("$resource/Profile/ServiceName/text() eq '"+ ANALYTICAL_TOOLKIT_SERVICE_GCORE_ENDPOINT_NAME +"'");
DiscoveryClient<GCoreEndpoint> client = clientFor(GCoreEndpoint.class);
List<GCoreEndpoint> toReturn = client.submit(query);
ScopeProvider.instance.set(currScope);
return toReturn;
}
public static String getAnalyticalToolkitEndpoint(String context) {
List<GCoreEndpoint> analyticalServices = null;
try {
analyticalServices = getAnalyticalToolkitServiceInstance(context);
if (analyticalServices == null || analyticalServices.isEmpty()) {
return "Cound not find Analytical Toolkit service";
}
GCoreEndpoint endpoint = analyticalServices.get(0);
Collection<Endpoint> list = endpoint.profile().endpoints().asCollection();
URI theURI = null;
for (Endpoint ep : list) {
if (ep.name().equals(ANALYTICAL_TOOLKIT_SERVICE_INTERFACE_NAME)) {
_log.info("Analytical Toolkit GCoreEndpoint: "+ep.uri());
theURI = ep.uri();
}
}
String endpointSSL = "https://"+theURI.getHost()+theURI.getPath();
_log.info("Returning endpointSSL " + endpointSSL);
return endpointSSL;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,23 @@
package org.gube.portlets.user.kpidata;
public enum PFISHGrowingStages {
GROW_OUT_INDIVIDUAL("Grow out Individual"),
GROW_OUT_INDIVIDUAL_CLOSED_BATCHES("Grow out Individual (closed)"),
GROW_OUT_AGGREGATED("Grow out Aggregated"),
GROW_OUT_AGGREGATED_CLOSED_BATCHES("Grow out Aggregated (closed)"),
HATCHERY_INDIVIDUAL("Hatchery Individual"),
HATCHERY_INDIVIDUAL_CLOSED_BATCHES("Hatchery Individual (closed)"),
PRE_ONGROWING("Pre-grow Individual"),
PRE_ONGROWING_CLOSED_BATCHES("Pre-grow Individual (closed)");
private String filename;
PFISHGrowingStages(String filename) {
this.filename = filename;
}
public String getFileName() {
return filename;
}
}

View File

@ -0,0 +1,238 @@
package org.gube.portlets.user.kpidata;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.net.ssl.HttpsURLConnection;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import org.apache.commons.io.IOUtils;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.storagehub.client.dsl.FolderContainer;
import org.gcube.common.storagehub.client.dsl.StorageHubClient;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
import org.gcube.common.storagehub.model.items.FolderItem;
import org.gcube.common.storagehub.model.items.Item;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.json.JSONArray;
import com.liferay.portal.kernel.json.JSONException;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.model.Group;
import com.liferay.portal.service.GroupLocalServiceUtil;
import com.liferay.portal.util.PortalUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;
/**
* Portlet implementation class PerformFISH_KPI_SnapshotData
*/
public class PerformFISH_KPI_SnapshotData extends MVCPortlet {
private static com.liferay.portal.kernel.log.Log _log = LogFactoryUtil.getLog(PerformFISH_KPI_SnapshotData.class);
private static final String KPI_DATA_FOLDER_NAME = "KPI-Data";
public static final String PERFORM_SERVICE_METHOD_ENDPOINT = "/performance?gcube-token=";
public void render(RenderRequest request, RenderResponse response) throws PortletException, IOException {
super.render(request, response);
}
public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException {
String token = "";
long groupId = 0;
String context = "";
String username = "";
try {
Group group = (Group) GroupLocalServiceUtil.getGroup(PortalUtil.getScopeGroupId(resourceRequest));
groupId = group.getGroupId();
context = KPIdataUtils.getCurrentContext(groupId);
username = PortalUtil.getUser(resourceRequest).getScreenName();
token = PortalContext.getConfiguration().getCurrentUserToken(context, username);
} catch (PortalException | SystemException e1) {
e1.printStackTrace();
}
resourceResponse.setContentType("application/json");
String endpoint = KPIdataUtils.getAnalyticalToolkitEndpoint(context);
String idFolderWhereToWriteFiles = createFoldersIfNotExists(token, context);
StringBuilder sb = new StringBuilder(endpoint)
.append(PERFORM_SERVICE_METHOD_ENDPOINT)
.append(token)
.append("&batch_type=");
_log.info("calling performService on context " + context);
List<CallResult> results = null;
try {
results = performAllCalls(sb.toString(), token, context, idFolderWhereToWriteFiles);
} catch (JSONException | IOException e) {
e.printStackTrace();
}
JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
for (CallResult result : results) {
JSONObject fileObject = JSONFactoryUtil.createJSONObject();
fileObject.put("success", result.isSuccess());
fileObject.put("comment", result.getComment());
jsonArray.put(fileObject);
}
resourceResponse.getWriter().println(jsonArray);
super.serveResource(resourceRequest, resourceResponse);
}
/**
*
* @param endpoint
* @param authorizationToken
* @param context
* @param folderOfTheDayId
* @return
* @throws JSONException
* @throws IOException
*/
private List<CallResult> performAllCalls(String endpoint, String authorizationToken, String context, String folderOfTheDayId) throws JSONException, IOException {
List<CallResult> callResults = new ArrayList<>();
for(PFISHGrowingStages type : PFISHGrowingStages.values()) {
_log.info(type + "-" + type.getFileName());
String request = endpoint+type;
JSONObject jsonObj = readFromURL(request);
ScopeProvider.instance.set(context);
SecurityTokenProvider.instance.set(authorizationToken);
StorageHubClient shc = new StorageHubClient();
Iterator<String> iterator = jsonObj.keys();
iterator.forEachRemaining((key) -> {
if (!key.endsWith("_internal")) {
StringBuilder sb = new StringBuilder(type.getFileName()).append(" - ").append(key).append(".csv");
String httpURLofTheCSV = jsonObj.getString(key);
boolean result = saveToWorkspaceVREFolder(shc, sb.toString(), httpURLofTheCSV, folderOfTheDayId);
callResults.add(new CallResult(result, sb.toString()));
}
});
}
return callResults;
}
/**
*
* @param filename
* @param fileURL
* @param authorizationToken
* @param context
* @param folderOfTheDayId
* @return
*/
private boolean saveToWorkspaceVREFolder(StorageHubClient shc, String filename, String fileURL, String folderOfTheDayId) {
try {
FolderContainer folderOfTheDay = shc.open(folderOfTheDayId).asFolder();
InputStream is = new URL(fileURL).openStream();
folderOfTheDay.uploadFile(is, filename, "");
_log.info("uploaded file " + filename + " with success");
} catch (Exception e) {
_log.error("Failed to upload file " + filename, e);
return false;
}
return true;
}
/**
*
* @param authorizationToken
* @param context
* @return the is of the folder for the day, it creates it of not existent
*/
private String createFoldersIfNotExists(String authorizationToken, String context) {
String idFolderWhereToWriteFiles = null;
ScopeProvider.instance.set(context);
SecurityTokenProvider.instance.set(authorizationToken);
StorageHubClient shc = new StorageHubClient();
FolderContainer vreFolder = shc.openVREFolder();
try {
List<? extends Item> items = vreFolder.list().getItems();
FolderContainer kpiDataFolder = null;
//verify that KPI_DATA_FOLDER_NAME folder exists, else create it
boolean kpiDataFolderExists = false;
for (Item item : items) {
if (item instanceof FolderItem && item.getName().equalsIgnoreCase(KPI_DATA_FOLDER_NAME)) {
kpiDataFolderExists = true;
kpiDataFolder = shc.open(item.getId()).asFolder();
break;
}
}
if (!kpiDataFolderExists)
kpiDataFolder = vreFolder.newFolder(KPI_DATA_FOLDER_NAME, "contains the generated data collected and anonymised");
//e.g. 2021-01-22
String folderOfTheDay = computeDayFoldername();
boolean folderOfTheDayExists = false;
for (Item item : kpiDataFolder.list().getItems()) {
if (item instanceof FolderItem && item.getName().equalsIgnoreCase(folderOfTheDay)) {
folderOfTheDayExists = true;
idFolderWhereToWriteFiles = item.getId();
}
}
if (!folderOfTheDayExists) {
idFolderWhereToWriteFiles = kpiDataFolder.newFolder(folderOfTheDay, "contains the generated data collected and anonymised for the day " + folderOfTheDay).getId();
_log.info("Created the folder for the day (" + folderOfTheDay + ") into KPI-Data Folder, returning id="+idFolderWhereToWriteFiles);
} else {
_log.info("The folder for the day (" + folderOfTheDay + ") exists already into KPI-Data Folder, returning id="+idFolderWhereToWriteFiles);
}
} catch (StorageHubException e) {
e.printStackTrace();
return null;
}
return idFolderWhereToWriteFiles;
}
/**
*
* @param request
* @return
* @throws IOException
* @throws JSONException
*/
private static JSONObject readFromURL(String request) throws IOException, JSONException {
URL url= new URL(null, request);
HttpsURLConnection conn= (HttpsURLConnection) url.openConnection();
conn.setDoOutput( true );
conn.setInstanceFollowRedirects( false );
conn.setRequestMethod( "GET" );
conn.setRequestProperty( "Content-Type", "application/json");
conn.setRequestProperty( "charset", "utf-8");
conn.setUseCaches( false );
InputStream in = conn.getInputStream();
String encoding = conn.getContentEncoding();
encoding = encoding == null ? "UTF-8" : encoding;
String body = IOUtils.toString(in, encoding);
JSONObject jsonObj = JSONFactoryUtil.createJSONObject(body);
return jsonObj;
}
//this returns the date as String as we want it: e.g. 2021-01-22
private String computeDayFoldername() {
String format = "yyyy-MM-dd";
DateFormat dateFormatter = new SimpleDateFormat(format);
String date = dateFormatter.format(new Date());
return date;
}
}

View File

@ -6,4 +6,7 @@
<portlet id="thematic-gateways-portlet"></portlet> <portlet id="thematic-gateways-portlet"></portlet>
<portlet id="vre-yard"></portlet> <portlet id="vre-yard"></portlet>
</category> </category>
<category name="category.sample">
<portlet id="perform-fish-kpi-snapshot-data"></portlet>
</category>
</display> </display>

View File

@ -22,6 +22,17 @@
</footer-portlet-javascript> </footer-portlet-javascript>
<css-class-wrapper>vre-yard-portlet</css-class-wrapper> <css-class-wrapper>vre-yard-portlet</css-class-wrapper>
</portlet> </portlet>
<portlet>
<portlet-name>perform-fish-kpi-snapshot-data</portlet-name>
<icon>/icon.png</icon>
<header-portlet-css>/css/main.css</header-portlet-css>
<footer-portlet-javascript>
/js/main.js
</footer-portlet-javascript>
<css-class-wrapper>
perform-fish-kpi-snapshot-data-portlet
</css-class-wrapper>
</portlet>
<role-mapper> <role-mapper>
<role-name>administrator</role-name> <role-name>administrator</role-name>
<role-link>Administrator</role-link> <role-link>Administrator</role-link>

View File

@ -67,4 +67,37 @@
<role-name>user</role-name> <role-name>user</role-name>
</security-role-ref> </security-role-ref>
</portlet> </portlet>
<portlet>
<portlet-name>perform-fish-kpi-snapshot-data</portlet-name>
<display-name>PerformFISH KPI Snapshot Data</display-name>
<portlet-class>
org.gube.portlets.user.kpidata.PerformFISH_KPI_SnapshotData
</portlet-class>
<init-param>
<name>view-template</name>
<value>/html/performfish_kpi_snapshotdata/view-kpi-data.jsp</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<portlet-info>
<title>PerformFISH KPI Snapshot Data</title>
<short-title>Perform Fish Kpi Snapshot Data</short-title>
<keywords></keywords>
</portlet-info>
<security-role-ref>
<role-name>administrator</role-name>
</security-role-ref>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power-user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
</portlet>
</portlet-app> </portlet-app>

View File

@ -0,0 +1,62 @@
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<%@include file="../init.jsp"%>
<portlet:defineObjects />
<portlet:resourceURL var="resourceURL">
</portlet:resourceURL>
<%
Group group = (Group) GroupLocalServiceUtil.getGroup(PortalUtil.getScopeGroupId(request));
long currentGroupId = group.getGroupId();
pageContext.setAttribute("groupId", currentGroupId);
%>
<script type="text/javascript">
function submitCallToPerformService(endpoint, groupId) {
console.log("submitCallToPerformService:" + endpoint);
$('#performServiceButton').attr("disabled", true);
$('#performServiceButton')
.html(
'<i class="icon-refresh icon-white">in progress ...please wait');
$('#feedbackResult').html('');
$.ajax({
url : endpoint,
type : 'POST',
datatype : 'json',
data : {
groupId : groupId,
userId : Liferay.ThemeDisplay.getUserId()
},
success : function(data) {
var resultArray = JSON.parse(JSON.stringify(data));
var feedbackResultHTML = '<p class="lead">Operation Result</p><ul>';
resultArray.forEach(item => {
var feedbackVisual = item.success ? ' <span style="color: green;">created succesfully</span> ' : ' <span style="color: red;">failed</span> ';
feedbackResultHTML += '<li>'+item.comment+':'+ feedbackVisual+'</li>';
});
feedbackResultHTML += '</ul>'
$('#feedbackResult').html(feedbackResultHTML);
$('#performServiceButton').hide();
$('#reloadPageButton').show();
}
});
}
</script>
<button name="snapshotdata" id="performServiceButton" type="button"
class="btn btn-primary"
onClick="submitCallToPerformService('${resourceURL}', '${groupId}')">Get
New Data</button>
<button name="refresh" id="reloadPageButton" type="button"
class="btn btn-primary" onClick="location.reload();">Please
click here to refresh the content of the folder, or to enable the Get
Data functionality again</button>
<div id="feedbackResult"></div>
<script>
$('#reloadPageButton').hide();
</script>

View File

@ -0,0 +1 @@