You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by dg...@apache.org on 2021/03/31 10:32:56 UTC

[unomi] 01/01: UNOMI-449 : forward existing endpoints to jax-rs endpoints

This is an automated email from the ASF dual-hosted git repository.

dgriffon pushed a commit to branch UNOMI-449-forward-public-endpoints
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit 794176bad4faa54eab1a30d58937aeee9f40c19b
Author: David Griffon <dg...@jahia.com>
AuthorDate: Wed Mar 31 12:32:32 2021 +0200

    UNOMI-449 : forward existing endpoints to jax-rs endpoints
---
 .../java/org/apache/unomi/rest/ClientEndpoint.java | 50 +++++++-----
 .../org/apache/unomi/rest/ContextJsonEndpoint.java | 91 +++++++++-------------
 .../apache/unomi/rest/EventsCollectorEndpoint.java | 56 ++++++-------
 3 files changed, 88 insertions(+), 109 deletions(-)

diff --git a/rest/src/main/java/org/apache/unomi/rest/ClientEndpoint.java b/rest/src/main/java/org/apache/unomi/rest/ClientEndpoint.java
index fb7f046..6d0f689 100644
--- a/rest/src/main/java/org/apache/unomi/rest/ClientEndpoint.java
+++ b/rest/src/main/java/org/apache/unomi/rest/ClientEndpoint.java
@@ -25,7 +25,6 @@ import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
 import org.apache.unomi.api.Profile;
 import org.apache.unomi.api.services.ConfigSharingService;
 import org.apache.unomi.api.services.ProfileService;
-import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
@@ -37,9 +36,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.io.OutputStream;
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -51,8 +48,6 @@ import java.util.Set;
  * A servlet filter to serve a context-specific Javascript containing the current request context object.
  */
 @WebService
-@Produces
-@Consumes(MediaType.TEXT_PLAIN)
 @CrossOriginResourceSharing(
         allowAllOrigins = true,
         allowCredentials = true
@@ -62,30 +57,40 @@ import java.util.Set;
 public class ClientEndpoint {
 
     private static final Logger logger = LoggerFactory.getLogger(ClientEndpoint.class.getName());
-    private static final long serialVersionUID = 2928875960103325238L;
+    private static final String CONTENT_DISPOSITION_HEADER_KEY = "Content-Disposition";
+
+    private static final String FILE_NAME_WO_EXT = "my-profile";
+
+    private static String getContentDispostionHeader(String extension) {
+        return String.format("attachment; filename=\"%s.%s\"", FILE_NAME_WO_EXT, extension);
+    }
 
     @Reference
     private ProfileService profileService;
     @Reference
     private ConfigSharingService configSharingService;
 
-    private final String FILE_NAME_WO_EXT = "my-profile";
 
     @Context
     HttpServletRequest request;
     @Context
     HttpServletResponse response;
 
+    @OPTIONS
+    @Path("/client/{operation}/{param}")
+    public Response options() {
+        return Response.status(Response.Status.NO_CONTENT).build();
+    }
+
     @GET
     @Path("/client/{operation}/{param}")
     public Response getClient(@PathParam("operation") String operation, @PathParam("param") String param) throws JsonProcessingException {
-        switch (operation) {
-            case "myprofile":
-                if (((String) configSharingService.getProperty("allowedProfileDownloadFormats")).contains(param)) {
-                    return donwloadCurrentProfile(param);
-                } else {
-                    throw new InternalServerErrorException(String.format("%s is not an allowed param", param));
-                }
+        if ("myprofile".equals(operation)) {
+            if (((String) configSharingService.getProperty("allowedProfileDownloadFormats")).contains(param)) {
+                return donwloadCurrentProfile(param);
+            } else {
+                throw new InternalServerErrorException(String.format("%s is not an allowed param", param));
+            }
         }
         throw new NotFoundException();
     }
@@ -112,8 +117,9 @@ public class ClientEndpoint {
                         return prepareCsvFileToDownload(currentProfile, request.getParameter("vertical") != null);
                     case "text":
                         return prepareYamlFileToDownload(currentProfile, true);
+                    default:
+                        throw new NotFoundException();
                 }
-
             }
         }
         throw new NotFoundException();
@@ -121,7 +127,8 @@ public class ClientEndpoint {
 
     private Response prepareCsvFileToDownload(Profile currentProfile, boolean vertical) {
         response.setContentType("text/csv");
-        response.setHeader("Content-Disposition", "attachment; filename=\"" + FILE_NAME_WO_EXT + ".csv\"");
+
+        response.setHeader(CONTENT_DISPOSITION_HEADER_KEY, getContentDispostionHeader("csv"));
         StringWriter writer = new StringWriter();
         //using custom delimiter and quote character
         CSVWriter csvWriter = new CSVWriter(writer);
@@ -132,12 +139,12 @@ public class ClientEndpoint {
             }
         } else {
             Set<String> keySet = currentProfile.getProperties().keySet();
-            List<String> values = new ArrayList();
+            List<String> values = new ArrayList<>();
             for (Object value : currentProfile.getProperties().values()) {
                 values.add(value.toString().trim().replace("\n", ""));
             }
-            csvWriter.writeNext(keySet.toArray(new String[keySet.size()]));
-            csvWriter.writeNext(values.toArray(new String[values.size()]));
+            csvWriter.writeNext(keySet.toArray(new String[0]));
+            csvWriter.writeNext(values.toArray(new String[0]));
         }
         Response.ResponseBuilder responseBuilder = Response.ok(writer.toString());
         return responseBuilder.build();
@@ -145,7 +152,8 @@ public class ClientEndpoint {
 
     private Response prepareJsonFileToDownload(Profile currentProfile) throws JsonProcessingException {
         response.setContentType("text/json");
-        response.setHeader("Content-Disposition", "attachment; filename=\"" + FILE_NAME_WO_EXT + ".json\"");
+        response.setHeader(CONTENT_DISPOSITION_HEADER_KEY, getContentDispostionHeader("json"));
+
         ObjectMapper mapper = new ObjectMapper();
         String jsonContent = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(currentProfile.getProperties());
         return Response.ok(jsonContent).build();
@@ -153,7 +161,7 @@ public class ClientEndpoint {
 
     private Response prepareYamlFileToDownload(Profile currentProfile, boolean asTextFile) throws JsonProcessingException {
         response.setContentType("text/" + (asTextFile ? "plain" : "yaml"));
-        response.setHeader("Content-Disposition", "attachment; filename=\"" + FILE_NAME_WO_EXT + (asTextFile ? ".txt" : ".yml") + "\"");
+        response.setHeader(CONTENT_DISPOSITION_HEADER_KEY, getContentDispostionHeader((asTextFile ? "txt" : "yml")));
         YAMLFactory yf = new YAMLFactory();
         ObjectMapper mapper = new ObjectMapper(yf);
         String yamlContent = mapper.writeValueAsString(currentProfile.getProperties());
diff --git a/rest/src/main/java/org/apache/unomi/rest/ContextJsonEndpoint.java b/rest/src/main/java/org/apache/unomi/rest/ContextJsonEndpoint.java
index 9a205ca..26e787c 100644
--- a/rest/src/main/java/org/apache/unomi/rest/ContextJsonEndpoint.java
+++ b/rest/src/main/java/org/apache/unomi/rest/ContextJsonEndpoint.java
@@ -17,15 +17,11 @@
 
 package org.apache.unomi.rest;
 
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.cxf.jaxrs.utils.ExceptionUtils;
 import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
 import org.apache.unomi.api.*;
 import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.services.*;
-import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.utils.Changes;
 import org.apache.unomi.utils.HttpUtils;
 import org.apache.unomi.utils.ServletCommon;
@@ -48,7 +44,7 @@ import java.util.*;
 
 @WebService
 @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
-@Consumes(MediaType.TEXT_PLAIN)
+@Consumes(MediaType.APPLICATION_JSON)
 @CrossOriginResourceSharing(
         allowAllOrigins = true,
         allowCredentials = true
@@ -82,9 +78,22 @@ public class ContextJsonEndpoint {
     @Reference
     private ConfigSharingService configSharingService;
 
+    @OPTIONS
+    @Path("/context.json")
+    public Response options() {
+        return Response.status(Response.Status.NO_CONTENT).header("Access-Control-Allow-Origin", "*").build();
+    }
+
     @POST
     @Path("/context.json")
-    public ContextResponse getContextJSON(String contextRequestAsString, @QueryParam("timestamp") Long timestampAsLong, @CookieParam("context-profile-id") String cookieProfileId) {
+    public ContextResponse getContextJSON(
+            ContextRequest contextRequest,
+            @QueryParam("personaId") String personaId,
+            @QueryParam("sessionId") String sessionId,
+            @QueryParam("timestamp") Long timestampAsLong,
+            @QueryParam("invalidateProfile") boolean invalidateProfile,
+            @QueryParam("invalidateSession") boolean invalidateSession
+    ) {
         Date timestamp = new Date();
         if (timestampAsLong != null) {
             timestamp = new Date(timestampAsLong);
@@ -93,7 +102,6 @@ public class ContextJsonEndpoint {
         // Handle persona
         Profile profile = null;
         Session session = null;
-        String personaId = request.getParameter("personaId");
         if (personaId != null) {
             PersonaWithSessions personaWithSessions = profileService.loadPersonaWithSessions(personaId);
             if (personaWithSessions == null) {
@@ -105,32 +113,16 @@ public class ContextJsonEndpoint {
             }
         }
 
-        // Extract payload
-        ContextRequest contextRequest = null;
         String scope = null;
-        String sessionId = null;
-        String profileId = null;
-        ObjectMapper mapper = CustomObjectMapper.getObjectMapper();
-        JsonFactory factory = mapper.getFactory();
-        try {
-            contextRequest = mapper.readValue(factory.createParser(contextRequestAsString), ContextRequest.class);
-        } catch (Exception e) {
-            logger.error("Cannot deserialize the context request payload. See debug level for more information");
-            if (logger.isDebugEnabled()) {
-                logger.debug("Cannot deserialize the context request payload because of {}", e.getMessage(), e);
-            }
-            throw ExceptionUtils.toHttpException(e, null);
-        }
         if (contextRequest.getSource() != null) {
             scope = contextRequest.getSource().getScope();
         }
-        sessionId = contextRequest.getSessionId();
-        profileId = contextRequest.getProfileId();
 
-        if (sessionId == null) {
-            sessionId = request.getParameter("sessionId");
+        if (contextRequest.getSessionId() != null) {
+            sessionId = contextRequest.getSessionId();
         }
 
+        String profileId = contextRequest.getProfileId();
         if (profileId == null) {
             // Get profile id from the cookie
             profileId = ServletCommon.getProfileIdCookieValue(request, (String) configSharingService.getProperty("profileIdCookieName"));
@@ -149,18 +141,16 @@ public class ContextJsonEndpoint {
             // Not a persona, resolve profile now
             boolean profileCreated = false;
 
-            boolean invalidateProfile = request.getParameter("invalidateProfile") != null ?
-                    new Boolean(request.getParameter("invalidateProfile")) : false;
             if (profileId == null || invalidateProfile) {
                 // no profileId cookie was found or the profile has to be invalidated, we generate a new one and create the profile in the profile service
-                profile = createNewProfile(null, response, timestamp);
+                profile = createNewProfile(null, timestamp);
                 profileCreated = true;
             } else {
                 profile = profileService.load(profileId);
                 if (profile == null) {
                     // this can happen if we have an old cookie but have reset the server,
                     // or if we merged the profiles and somehow this cookie didn't get updated.
-                    profile = createNewProfile(profileId, response, timestamp);
+                    profile = createNewProfile(profileId, timestamp);
                     profileCreated = true;
                 } else {
                     Changes changesObject = checkMergedProfile(profile, session);
@@ -170,8 +160,6 @@ public class ContextJsonEndpoint {
             }
 
             Profile sessionProfile;
-            boolean invalidateSession = request.getParameter("invalidateSession") != null ?
-                    new Boolean(request.getParameter("invalidateSession")) : false;
             if (StringUtils.isNotBlank(sessionId) && !invalidateSession) {
                 session = profileService.loadSession(sessionId, timestamp);
                 if (session != null) {
@@ -256,11 +244,9 @@ public class ContextJsonEndpoint {
             contextResponse.setSessionId(sessionId);
         }
 
-        if (contextRequest != null) {
-            Changes changesObject = handleRequest(contextRequest, session, profile, contextResponse, request, response, timestamp);
-            changes |= changesObject.getChangeType();
-            profile = changesObject.getProfile();
-        }
+        Changes changesObject = handleRequest(contextRequest, session, profile, contextResponse, request, response, timestamp);
+        changes |= changesObject.getChangeType();
+        profile = changesObject.getProfile();
 
         if ((changes & EventService.PROFILE_UPDATED) == EventService.PROFILE_UPDATED) {
             profileService.save(profile);
@@ -296,7 +282,6 @@ public class ContextJsonEndpoint {
                 }
             } else {
                 logger.warn("Couldn't find merged profile {}, falling back to profile {}", masterProfileId, currentProfile.getItemId());
-                profile = currentProfile;
                 profile.setMergedWith(null);
                 changes = EventService.PROFILE_UPDATED;
             }
@@ -379,25 +364,23 @@ public class ContextJsonEndpoint {
      * @param session
      */
     private void processOverrides(ContextRequest contextRequest, Profile profile, Session session) {
-        if (profile instanceof Persona) {
-            if (contextRequest.getProfileOverrides() != null) {
-                if (contextRequest.getProfileOverrides().getScores() != null) {
-                    profile.setScores(contextRequest.getProfileOverrides().getScores());
-                }
-                if (contextRequest.getProfileOverrides().getSegments() != null) {
-                    profile.setSegments(contextRequest.getProfileOverrides().getSegments());
-                }
-                if (contextRequest.getProfileOverrides().getProperties() != null) {
-                    profile.setProperties(contextRequest.getProfileOverrides().getProperties());
-                }
-                if (contextRequest.getSessionPropertiesOverrides() != null && session != null) {
-                    session.setProperties(contextRequest.getSessionPropertiesOverrides());
-                }
+        if (profile instanceof Persona && contextRequest.getProfileOverrides() != null) {
+            if (contextRequest.getProfileOverrides().getScores() != null) {
+                profile.setScores(contextRequest.getProfileOverrides().getScores());
+            }
+            if (contextRequest.getProfileOverrides().getSegments() != null) {
+                profile.setSegments(contextRequest.getProfileOverrides().getSegments());
+            }
+            if (contextRequest.getProfileOverrides().getProperties() != null) {
+                profile.setProperties(contextRequest.getProfileOverrides().getProperties());
+            }
+            if (contextRequest.getSessionPropertiesOverrides() != null && session != null) {
+                session.setProperties(contextRequest.getSessionPropertiesOverrides());
             }
         }
     }
 
-    private Profile createNewProfile(String existingProfileId, ServletResponse response, Date timestamp) {
+    private Profile createNewProfile(String existingProfileId, Date timestamp) {
         Profile profile;
         String profileId = existingProfileId;
         if (profileId == null) {
@@ -443,7 +426,7 @@ public class ContextJsonEndpoint {
         List<PersonalizationService.PersonalizationRequest> result = new ArrayList<>();
         for (PersonalizationService.PersonalizationRequest personalizationRequest : personalizations) {
             List<PersonalizationService.PersonalizedContent> personalizedContents = sanitizePersonalizedContentObjects(personalizationRequest.getContents());
-            if (personalizedContents != null && personalizedContents.size() > 0) {
+            if (personalizedContents != null && !personalizedContents.isEmpty()) {
                 result.add(personalizationRequest);
             }
         }
diff --git a/rest/src/main/java/org/apache/unomi/rest/EventsCollectorEndpoint.java b/rest/src/main/java/org/apache/unomi/rest/EventsCollectorEndpoint.java
index a673fd3..e0e603a 100644
--- a/rest/src/main/java/org/apache/unomi/rest/EventsCollectorEndpoint.java
+++ b/rest/src/main/java/org/apache/unomi/rest/EventsCollectorEndpoint.java
@@ -17,43 +17,33 @@
 
 package org.apache.unomi.rest;
 
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
-import org.apache.unomi.api.Event;
-import org.apache.unomi.api.EventsCollectorRequest;
-import org.apache.unomi.api.Persona;
-import org.apache.unomi.api.Profile;
-import org.apache.unomi.api.Session;
+import org.apache.unomi.api.*;
 import org.apache.unomi.api.services.ConfigSharingService;
 import org.apache.unomi.api.services.EventService;
 import org.apache.unomi.api.services.PrivacyService;
 import org.apache.unomi.api.services.ProfileService;
-import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.utils.Changes;
 import org.apache.unomi.utils.ServletCommon;
-import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.jws.WebService;
-import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
-import java.io.IOException;
-import java.rmi.RemoteException;
+import javax.ws.rs.core.Response;
 import java.util.Date;
 import java.util.UUID;
 
 @WebService
 @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
-@Consumes(MediaType.TEXT_PLAIN)
+@Consumes(MediaType.APPLICATION_JSON)
 @CrossOriginResourceSharing(
         allowAllOrigins = true,
         allowCredentials = true
@@ -77,36 +67,30 @@ public class EventsCollectorEndpoint {
     @Context
     HttpServletResponse response;
 
+    @OPTIONS
+    @Path("/eventcollector")
+    public Response options() {
+        return Response.status(Response.Status.NO_CONTENT).build();
+    }
+
     @GET
     @Path("/eventcollector")
-    public EventCollectorResponse get(String eventsCollectorRequestAsString, @QueryParam("timestamp") Long timestampAsString) throws IOException {
-        return doEvent(eventsCollectorRequestAsString, timestampAsString);
+    public EventCollectorResponse collectAsGet(EventsCollectorRequest eventsCollectorRequest, @QueryParam("timestamp") Long timestampAsString) {
+        return doEvent(eventsCollectorRequest, timestampAsString);
     }
 
     @POST
     @Path("/eventcollector")
-    public EventCollectorResponse post(String eventsCollectorRequestAsString, @QueryParam("timestamp") Long timestampAsLong) throws IOException {
-        return doEvent(eventsCollectorRequestAsString, timestampAsLong);
+    public EventCollectorResponse collectAsPost(EventsCollectorRequest eventsCollectorRequest, @QueryParam("timestamp") Long timestampAsLong) {
+        return doEvent(eventsCollectorRequest, timestampAsLong);
     }
 
-    private EventCollectorResponse doEvent(String eventsCollectorRequestAsString, Long timestampAsLong) throws IOException {
+    private EventCollectorResponse doEvent(EventsCollectorRequest eventsCollectorRequest, Long timestampAsLong) {
         Date timestamp = new Date();
         if (timestampAsLong != null) {
             timestamp = new Date(timestampAsLong);
         }
 
-
-        ObjectMapper mapper = CustomObjectMapper.getObjectMapper();
-        JsonFactory factory = mapper.getFactory();
-        EventsCollectorRequest eventsCollectorRequest;
-        try {
-            eventsCollectorRequest = mapper.readValue(factory.createParser(eventsCollectorRequestAsString), EventsCollectorRequest.class);
-        } catch (Exception e) {
-            if (logger.isDebugEnabled()) {
-                logger.debug("Cannot parse eventsCollectorRequest: {}", eventsCollectorRequestAsString, e);
-            }
-            throw new RemoteException("Cannot read payload. See debug level for more information");
-        }
         if (eventsCollectorRequest == null || eventsCollectorRequest.getEvents() == null) {
             throw new InternalServerErrorException("No events found");
         }
@@ -125,8 +109,8 @@ public class EventsCollectorEndpoint {
             // Get the first available scope that is not equal to systemscope to create the session otherwise systemscope will be used
             for (Event event : eventsCollectorRequest.getEvents()) {
                 if (StringUtils.isNotBlank(event.getEventType())) {
-                    if (StringUtils.isNotBlank(event.getScope()) && !event.getScope().equals("systemscope")) {
-                        scope = event.getScope();
+                    if (StringUtils.isNotBlank(event.getSourceId()) && !event.getSourceId().equals("systemscope")) {
+                        scope = event.getSourceId();
                         break;
                     } else if (event.getSource() != null && StringUtils.isNotBlank(event.getSource().getScope()) && !event.getSource().getScope().equals("systemscope")) {
                         scope = event.getSource().getScope();
@@ -134,6 +118,7 @@ public class EventsCollectorEndpoint {
                     }
                 }
             }
+            logger.debug("scope is now {}", scope);
             String cookieProfileId = ServletCommon.getProfileIdCookieValue(request, (String) configSharingService.getProperty("profileIdCookieName"));
             if (StringUtils.isNotBlank(cookieProfileId)) {
                 profile = profileService.load(cookieProfileId);
@@ -154,11 +139,13 @@ public class EventsCollectorEndpoint {
             */
         } else {
             Profile sessionProfile = session.getProfile();
+            final String errorMessage = String.format("No valid profile found or persona found for profileId=%s, aborting request !", session.getProfileId());
             if (sessionProfile.getItemId() != null) {
                 // Reload up-to-date profile
                 profile = profileService.load(sessionProfile.getItemId());
                 if (profile == null || profile instanceof Persona) {
-                    throw new InternalServerErrorException(String.format("No valid profile found or persona found for profileId=%s, aborting request !", session.getProfileId()));
+                    logger.error(errorMessage);
+                    throw new InternalServerErrorException(errorMessage);
                 }
             } else {
                 // Session uses anonymous profile, try to find profile from cookie
@@ -168,7 +155,8 @@ public class EventsCollectorEndpoint {
                 }
 
                 if (profile == null) {
-                    throw new InternalServerErrorException(String.format("No valid profile found or persona found for profileId=%s, aborting request !", session.getProfileId()));
+                    logger.error(errorMessage);
+                    throw new InternalServerErrorException(errorMessage);
                 }
             }
         }